1
0
mirror of https://github.com/nophead/NopSCADlib.git synced 2025-09-09 14:40:44 +02:00

Moved printed parts to their own directory.

This commit is contained in:
Chris Palmer
2019-06-11 23:20:28 +01:00
parent b1fb0286b5
commit 258d4e88ae
38 changed files with 141 additions and 82 deletions

471
printed/box.scad Normal file
View File

@@ -0,0 +1,471 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! A box made from routed or laser cut sheet sheets and printed profiles and bezels. It can be arbitrarily large
//! compared to the 3D printed parts because they can be cut into interlocking sections and solvent welded
//! together. The box panels can be customised to have holes and parts mounted on them by overriding the
//! definitions of `box_base()`, `box_front()`, etc.
//!
//! `box.scad` should be ```use```d and `box_assembly.scad` ```include```d.
//!
//! A box is defined with a list that specifies the inside dimensions, top, bottom and side sheet materials, the
//! screw type and printed part wall thickness. This diagram shows how the various dimensions are labelled:
//! ![](docs/box.png)
//!
//! Normally the side sheets are the same type but they can be overridden individually as long as the substitute has the same thickness.
//
include <../core.scad>
use <../vitamins/sheet.scad>
use <../vitamins/screw.scad>
use <../vitamins/washer.scad>
include <../vitamins/inserts.scad>
use <../utils/quadrant.scad>
bezel_clearance = 0.2;
sheet_end_clearance = 1;
sheet_slot_clearance = 0.2;
function box_screw(type) = type[0]; //! Screw type to be used at the corners
function box_wall(type) = type[1]; //! Wall thickness of 3D parts
function box_sheets(type) = type[2]; //! Sheet type used for the sides
function box_top_sheet(type) = type[3]; //! Sheet type for the top
function box_base_sheet(type)= type[4]; //! Sheet type for the bottom
function box_feet(type) = type[5]; //! True to enable feet on the bottom bezel
function box_width(type) = type[6]; //! Internal width
function box_depth(type) = type[7]; //! Internal depth
function box_height(type) = type[8]; //! Internal height
function box_bezel_clearance(type) = bezel_clearance;
function box_corner_gap(type) = 3; //! Gap between box_sheets at the corners to connect inside and outside profiles
function box_profile_overlap(type) = 3 + sheet_end_clearance / 2;
function box_washer(type) = screw_washer(box_screw(type));
function box_insert(type) = screw_insert(box_screw(type));
function box_hole_inset(type) = washer_radius(box_washer(type)) + 1;
function box_insert_r(type) = insert_hole_radius(box_insert(type));
function box_insert_l(type) = insert_length(box_insert(type));
function box_boss_r(type) = ceil(corrected_radius(box_insert_r(type)) + box_wall(type));
function box_sheet_slot(type) = sheet_thickness(box_sheets(type)) + sheet_slot_clearance; // add some clearance
function box_corner_overlap(type) = box_wall(type);
function box_corner_rad(type) = box_sheet_slot(type) - sheet_slot_clearance / 2 + box_corner_gap(type) + box_corner_overlap(type);
function box_sheet_r(type) = box_corner_rad(type) - box_sheet_slot(type) - box_corner_overlap(type);
function box_screw_length(type, top) = screw_longer_than(2 * washer_thickness(box_washer(type))
+ sheet_thickness(top ? box_top_sheet(type) : box_base_sheet(type))
+ box_corner_gap(type) + box_profile_overlap(type) + box_insert_l(type) - 1);
function box_wall_clearance(type) = box_sheet_slot(type) / 2 - sheet_thickness(box_sheets(type)) / 2;
function box_margin(type) = box_profile_overlap(type) + box_corner_gap(type); //! How much the bezel intrudes on the specified height
function box_intrusion(type) = box_hole_inset(type) + box_boss_r(type); //! Corner profile intrusion
function sheet_reduction(type) = 2 * box_corner_gap(type) + sheet_end_clearance;
function box_outset(type) = box_sheet_slot(type) + box_wall(type) - sheet_slot_clearance / 2; //! How much the bezel expands the specified internal size
function box_inset(type) = box_wall(type) + sheet_slot_clearance / 2; //! How much the bezel intrudes on the specified width and length, away from the corners
function box_bezel_height(type, bottom) = //! Bezel height for top or bottom
let(t1 = sheet_thickness(box_base_sheet(type)), t2 = sheet_thickness(box_top_sheet(type)))
box_corner_rad(type) + box_profile_overlap(type) + (bottom ? max(t1, t2) : t2) - sheet_thickness(box_sheets(type));
grill_hole = 5;
grill_gap = 1.9;
module grill(width, height, r = 1000, poly = false, h = 0) { //! A staggered array of 5mm holes to make grills in sheets. Can be constrained to be circular. Set ```poly``` ```true``` for printing, ```false``` for milling.
nx = floor(width / (grill_hole + grill_gap));
xpitch = width / nx;
ny = floor(height / ((grill_hole + grill_gap) * cos(30)));
ypitch = height / ny;
extrude_if(h)
for(y = [0 : ny - 1], x = [0 : nx - 1 - (y % 2)]) {
x = -width / 2 + (x + 0.5 + (y % 2) / 2) * xpitch;
y = -height / 2 + (y + 0.5) * ypitch;
if(sqrt(sqr(x) + sqr(y)) + grill_hole / 2 <= r)
translate([x, y])
if(poly)
poly_circle(r = grill_hole / 2);
else
circle(d = grill_hole);
}
}
module box_corner_profile_2D(type) { //! The 2D shape of the corner profile.
t = box_sheet_slot(type);
difference() {
union() {
quadrant(box_hole_inset(type) + box_boss_r(type), box_boss_r(type)); // inside corner
translate([box_corner_gap(type) + box_profile_overlap(type), box_corner_gap(type) + box_profile_overlap(type)])
rotate(180)
quadrant(box_profile_overlap(type) + box_corner_rad(type), box_corner_rad(type)); // outside corner
}
translate([box_corner_gap(type), -t + sheet_slot_clearance / 2])
square([100, t]);
translate([-t + sheet_slot_clearance / 2, box_corner_gap(type)])
square([t, 100]);
}
}
module box_corner_profile(type) { //! Generates the corner profile STL for 3D printing.
stl("box_corner_profile");
length = box_height(type) - 2 * box_margin(type);
difference() {
linear_extrude(height = length, center = true, convexity = 5)
box_corner_profile_2D(type);
for(z = [-1, 1])
translate([box_hole_inset(type), box_hole_inset(type), z * length / 2])
insert_hole(box_insert(type), 5);
}
}
module box_corner_profile_section(type, section, sections) { //! Generates interlocking sections of the corner profile to allow it to be taller than the printer
overlap = 4;
length = box_height(type) - 2 * box_margin(type);
section_length = round_to_layer((length - overlap) / sections);
last_section = section >= sections - 1;
h = last_section ? length - (sections - 1) * section_length : section_length;
overlap_wall = 2;
difference() {
union() {
linear_extrude(height = h, convexity = 5)
box_corner_profile_2D(type);
if(!last_section) // male end always at the top
translate_z(section_length - 1)
for(i = [0 : 1], offset = i * layer_height)
linear_extrude(height = overlap + 1 - offset)
offset(1 + offset - layer_height)
offset(-overlap_wall - 1)
box_corner_profile_2D(type);
}
if(section > 0)
translate_z(last_section ? h : 0) { // female at bottom unless last section
linear_extrude(height = 2 * (overlap + layer_height), center = true, convexity = 5)
offset(-overlap_wall)
box_corner_profile_2D(type);
linear_extrude(height = 2 * layer_height, center = true, convexity = 5)
offset(-overlap_wall + layer_height)
box_corner_profile_2D(type);
}
if(!section || last_section) // insert holes always at the bottom
translate([box_hole_inset(type), box_hole_inset(type)])
insert_hole(box_insert(type), 5);
}
}
module box_corner_quadrants(type, width, depth)
for(corner = [0:3]) {
x = [-1,1,1,-1][corner];
y = [-1,-1,1,1][corner];
translate([x * width / 2, y * depth / 2, 0])
rotate(corner * 90)
quadrant(box_intrusion(type), box_boss_r(type));
}
module box_bezel(type, bottom) { //! Generates top and bottom bezel STLs
stl(bottom ? "bottom_bezel" : "top_bezel");
feet = bottom && box_feet(type);
t = box_sheet_slot(type);
outset = box_outset(type);
inner_r = box_sheet_r(type);
foot_height = box_corner_gap(type) + sheet_thickness(box_base_sheet(type)) + washer_thickness(box_washer(type)) + screw_head_height(box_screw(type)) + box_profile_overlap(type) + 2;
foot_length = box_corner_rad(type) * 2;
height = box_bezel_height(type, bottom);
foot_extension = foot_height - height;
difference() {
translate_z(-box_profile_overlap(type)) difference() {
rounded_rectangle([box_width(type) + 2 * outset, box_depth(type) + 2 * outset, feet ? foot_height : height], box_corner_rad(type), false);
//
// Remove edges between the feet
//
if(feet)
hull() {
translate_z(height + 0.5)
cube([box_width(type) - 2 * foot_length, box_depth(type) + 2 * outset + 1, 1], center = true);
translate_z(foot_height + 1)
cube([box_width(type) - 2 * (foot_length - foot_extension), box_depth(type) + 2 * outset + 1, 1], center = true);
}
if(feet)
hull() {
translate_z(height + 0.5)
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * foot_length, 1], center = true);
translate_z(foot_height + 1)
cube([box_width(type) + 2 * outset + 1, box_depth(type) - 2 * (foot_length - foot_extension), 1], center = true);
}
}
//
// slots for side panels
//
translate_z(-box_profile_overlap(type))
linear_extrude(height = 2 * box_profile_overlap(type), center = true)
for(i = [-1, 1]) {
translate([i * (box_width(type) / 2 + t / 2 - sheet_slot_clearance / 2), 0])
square([t, box_depth(type) - 2 * box_corner_gap(type)], center = true);
translate([0, i * (box_depth(type) / 2 + t / 2 - sheet_slot_clearance / 2)])
square([box_width(type) - 2 * box_corner_gap(type), t], center = true);
}
//
// recess for top / bottom panel
//
translate_z(box_corner_gap(type))
rounded_rectangle([box_width(type) + bezel_clearance, box_depth(type) + bezel_clearance, height], inner_r + bezel_clearance / 2, false);
//
// leave plastic over the corner profiles
//
translate_z(-box_profile_overlap(type) - 1)
linear_extrude(height = box_profile_overlap(type) + box_corner_gap(type) + 2)
union() {
difference() {
square([box_width(type) - 2 * box_inset(type),
box_depth(type) - 2 * box_inset(type)], center = true);
box_corner_quadrants(type, box_width(type), box_depth(type));
}
box_screw_hole_positions(type)
poly_circle(screw_clearance_radius(box_screw(type)));
}
}
}
dowel_length = 20;
dowel_wall = extrusion_width * 3;
dowel_h_wall = layer_height * 6;
module box_bezel_section(type, bottom, rows, cols, x, y) { //! Generates interlocking sections of the bezel to allow it to be bigger than the printer
w = (box_width(type) + 2 * box_outset(type)) / cols;
h = (box_depth(type) + 2 * box_outset(type)) / rows;
bw = box_outset(type) - bezel_clearance / 2;
bw2 = box_outset(type) + box_inset(type);
dw = bw - 2 * dowel_wall;
dh = box_bezel_height(type, bottom) - dowel_h_wall;
dh2 = box_profile_overlap(type) + box_corner_gap(type) - dowel_h_wall;
end_clearance = 0.5;
module male() {
rotate([90, 0, 90])
linear_extrude(height = dowel_length - 2 * end_clearance, center = true)
difference() {
union() {
h = dh - layer_height;
h2 = dh2 - layer_height;
hull() {
translate([bw / 2, h / 2])
square([dw - 1, h], center = true);
translate([bw / 2, (h - 1) / 2])
square([dw, h - 1], center = true);
}
hull() {
translate([bw2 / 2, h2 / 2])
square([bw2 - 2 * dowel_wall - 1, h2], center = true);
translate([bw2 / 2, (h2 - 1) / 2])
square([bw2 - 2 * dowel_wall, h2 - 1], center = true);
}
}
translate([bw2 / 2, 0])
square([box_sheet_slot(type), 2 * box_profile_overlap(type)], center = true);
}
}
module female() {
union() {
translate([0, bw / 2, dh / 2])
cube([dowel_length, dw, dh], center = true);
translate([0, bw2 / 2])
cube([dowel_length, bw2 - 2 * dowel_wall, dh2 * 2], center = true);
hull() {
translate([0, bw / 2, dh / 2])
cube([2, dw, dh], center = true);
translate([0, bw / 2, dh / 2])
cube([eps, dw + 2 * extrusion_width, dh], center = true);
}
hull() {
translate([0, bw2 / 2, dh2 / 2])
cube([2, bw2 - 2 * dowel_wall, dh2], center = true);
translate([0, bw2 / 2, dh2 / 2])
cube([eps, bw2 - 2 * dowel_wall + 2 * extrusion_width, dh2], center = true);
}
}
}
module support() {
if(!$preview)
translate([0, bw / 2 + dw / 2])
cube([dowel_length / 2 - 0.25, 2 * extrusion_width + 0.2, dh2]);
}
union() {
render() difference() {
union() {
clip(xmin = 0, xmax = w, ymin = 0, ymax = h)
translate([box_width(type) / 2 + box_outset(type) - x * w, box_depth(type) / 2 + box_outset(type) - y * h, box_profile_overlap(type)])
box_bezel(type, bottom);
if(x < cols - 1 && y == 0)
translate([w, 0])
male();
if(x > 0 && y == rows - 1)
translate([0, h])
rotate(180)
male();
if(y < rows - 1 && x == cols - 1)
translate([w, h])
rotate(90)
male();
if(y > 0 && x == 0)
rotate(-90)
male();
}
if(x < cols - 1 && y == rows - 1)
translate([w, h])
rotate(180)
female();
if(x > 0 && y == 0)
female();
if(y < rows - 1 && x == 0)
translate([0, h])
rotate(-90)
female();
if(y > 0 && x == cols - 1)
translate([w, 0])
rotate(90)
female();
}
if(x < cols - 1 && y == rows - 1)
translate([w, h])
rotate(180)
support();
if(x > 0 && y == 0)
support();
if(y < rows - 1 && x == 0)
translate([0, h])
rotate(-90)
support();
if(y > 0 && x == cols - 1)
translate([w, 0])
rotate(90)
support();
}
}
module box_shelf_blank(type) { //! Generates a 2D template for a shelf sheet
dxf("box_shelf");
difference() {
sheet_2D(box_sheets(type), box_width(type) - bezel_clearance, box_depth(type) - bezel_clearance, 1);
offset(bezel_clearance / 2)
box_corner_quadrants(type, box_width(type), box_depth(type));
}
}
module box_screw_hole_positions(type)
for(x = [-1, 1], y = [-1, 1])
translate([x * (box_width(type) / 2 - box_hole_inset(type)), y * (box_depth(type) / 2 - box_hole_inset(type))])
children();
module box_base_blank(type) { //! Generates a 2D template for the base sheet
dxf("box_base");
difference() {
sheet_2D(box_base_sheet(type), box_width(type), box_depth(type), box_sheet_r(type));
box_screw_hole_positions(type)
drill(screw_clearance_radius(box_screw(type)), 0);
}
}
module box_top_blank(type) { //! Generates a 2D template for the top sheet
dxf("box_top");
difference() {
sheet_2D(box_top_sheet(type), box_width(type), box_depth(type), box_sheet_r(type));
box_screw_hole_positions(type)
drill(screw_clearance_radius(box_screw(type)), 0);
}
}
function subst_sheet(type, sheet) =
let(s = box_sheets(type))
sheet ? assert(sheet_thickness(sheet) == sheet_thickness(s)) sheet : s;
module box_left_blank(type, sheet = false) { //! Generates a 2D template for the left sheet, ```sheet``` can be set to override the type
dxf("box_left");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_right_blank(type, sheet = false) { //! Generates a 2D template for the right sheet, ```sheet``` can be set to override the type
dxf("box_right");
sheet_2D(subst_sheet(type, sheet), box_depth(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_front_blank(type, sheet = false) { //! Generates a 2D template for the front sheet, ```sheet``` can be set to override the type
dxf("box_front");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_back_blank(type, sheet = false) { //! Generates a 2D template for the back sheet, ```sheet``` can be set to override the type
dxf("box_back");
sheet_2D(subst_sheet(type, sheet), box_width(type) - sheet_reduction(type), box_height(type) - sheet_reduction(type), 1);
}
module box_base(type) render_2D_sheet(box_base_sheet(type)) box_base_blank(type); //! Default base, can be overridden to customise
module box_top(type) render_2D_sheet(box_top_sheet(type)) box_top_blank(type); //! Default top, can be overridden to customise
module box_back(type) render_2D_sheet(box_sheets(type)) box_back_blank(type); //! Default back, can be overridden to customise
module box_front(type) render_2D_sheet(box_sheets(type)) box_front_blank(type); //! Default front, can be overridden to customise
module box_left(type) render_2D_sheet(box_sheets(type)) box_left_blank(type); //! Default left side, can be overridden to customise
module box_right(type) render_2D_sheet(box_sheets(type)) box_right_blank(type); //! Default right side, can be overridden to customise

94
printed/box_assembly.scad Normal file
View File

@@ -0,0 +1,94 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
// The assembly is ```include```d so the panel definitions can be overridden to add holes and components.
// The _box_module also needs to be wrapped in the file that uses it so it can be called without
// parameters to make the assembly views. E.g. module box_assembly() _box_assembly(box);
//
module _box_assembly(type, top = true, base = true, left = true, right = true, back = true, front = true, bezels = true, corners = 4)
assembly("box") {
echo("Box:", box_width(type), box_depth(type), box_height(type));
t = sheet_thickness(box_sheets(type));
for(corner = [0 : corners - 1]) {
x = [-1,1,1,-1][corner];
y = [-1,-1,1,1][corner];
translate([x * (box_width(type) / 2 + 25 * exploded()), y * (box_depth(type) / 2 + 25 * exploded())])
rotate(corner * 90) {
color(pp2_colour) render()
box_corner_profile(type);
translate([box_hole_inset(type), box_hole_inset(type)])
for(z = [-1, 1])
rotate([z * 90 -90, 0, 0])
translate_z(box_height(type) / 2 - box_margin(type))
insert(box_insert(type));
}
}
for(z = [-1, 1]) {
sheet_thickness = sheet_thickness(z > 0 ? box_top_sheet(type) : box_base_sheet(type));
translate_z(z * (box_height(type) / 2 - box_corner_gap(type) + 50 * exploded()))
rotate([z * 90 - 90, 0, 0])
if(bezels && (z > 0 ? top : base))
color(pp1_colour) render() box_bezel(type, z < 0);
translate_z(z * (box_height(type) / 2 + sheet_thickness + 50 * exploded()))
box_screw_hole_positions(type)
rotate([z * 90 -90, 0, 0])
explode(50, true)
screw_and_washer(box_screw(type), box_screw_length(type, z > 0), true);
}
for(x = [-1, 1])
translate([x * (box_width(type) / 2 + t / 2 + 25 * exploded()), 0])
rotate([90, 0, x * 90])
if(x > 0) {
if(right)
box_right(type);
}
else
if(left)
box_left(type);
for(y = [-1, 1])
translate([0, y * (box_depth(type) / 2 + t / 2 + 25 * exploded())])
rotate([90, 0, y * 90 + 90])
if(y < 0) {
if(front)
box_front(type);
}
else
if(back)
box_back(type);
for(z = [-1, 1]) {
sheet_thickness = sheet_thickness(z > 0 ? box_top_sheet(type) : box_base_sheet(type));
translate_z(z * (box_height(type) / 2 + sheet_thickness / 2 + eps + 100 * exploded()))
if(z > 0) {
if(top)
box_top(type);
}
else
if(base)
box_base(type);
}
}

261
printed/butt_box.scad Normal file
View File

@@ -0,0 +1,261 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! A box made from CNC cut panels butted together using printed fixing blocks. Useful for making large
//! boxes with minimal 3D printing. More blocks are added as the box gets bigger.
//!
//! Needs to be ```include```d rather than ```use```d to allow the panel definitions to be overridden to add holes
//! and mounted components.
//!
//! A list specifies the internal dimensions, screw type, top, bottom and side sheet types and the block
//! maximum spacing.
//!
//! Uses [fixing blocks](#fixing_block) and [corner blocks](#corner_block).
//
use <fixing_block.scad>
use <corner_block.scad>
use <../utils/maths.scad>
function bbox_screw(type) = type[0]; //! Screw type for corner blocks
function bbox_sheets(type) = type[1]; //! Sheet type for the sides
function bbox_base_sheet(type)= type[2]; //! Sheet type for the base
function bbox_top_sheet(type) = type[3]; //! Sheet type for the top
function bbox_span(type) = type[4]; //! Maximum span between fixing blocks
function bbox_width(type) = type[5]; //! Internal width
function bbox_depth(type) = type[6]; //! Internal depth
function bbox_height(type) = type[7]; //! Internal height
module bbox_shelf_blank(type) { //! 2D template for a shelf
dxf("bbox_shelf");
sheet_2D(bbox_sheets(type), bbox_width(type), bbox_depth(type), 1);
}
function corner_block_positions(type) = let(
width = bbox_width(type),
depth = bbox_depth(type),
height = bbox_height(type)
)
[for(corner = [0 : 3], z = [-1, 1])
let(
x = [-1,1,1,-1][corner],
y = [-1,-1,1,1][corner]
) translate([x * (width / 2), y * (depth / 2), z * height / 2]) *
rotate([z > 0 ? 180 : 0, 0, corner * 90 + (z > 0 ? 90 : 0)])
];
module corner_block_positions(type) {
bt = sheet_thickness(bbox_base_sheet(type));
tt = sheet_thickness(bbox_top_sheet(type));
for(p = corner_block_positions(type))
let($thickness = transform([0, 0, 0], p).z > 0 ? tt : bt)
multmatrix(p)
children();
}
function corner_holes(type) = [for(p = corner_block_positions(type), q = corner_block_holes(bbox_screw(type))) p * q];
function fixing_block_positions(type) = let(
width = bbox_width(type),
depth = bbox_depth(type),
height = bbox_height(type),
span = bbox_span(type),
wspans = floor(width / span),
wspan = width / (wspans + 1),
dspans = floor(depth / span),
dspan = depth / (dspans + 1),
hspans = floor(height / span),
hspan = height / (hspans + 1)
)
[
for(i = [0 : 1 : wspans - 1], y = [-1, 1], z = [-1, 1])
translate([(i - (wspans - 1) / 2) * wspan, y * depth / 2, z * height / 2]) *
rotate([0, z * 90 + 90, y * 90 + 90]),
for(i = [0 : 1 : dspans - 1], x = [-1, 1], z = [-1, 1])
translate([x * width / 2, (i - (dspans - 1) / 2) * dspan, z * height / 2]) *
rotate([0, z * 90 + 90, x * 90]),
for(i = [0 : 1 : hspans - 1], x = [-1, 1], y = [-1, 1])
translate([x * width / 2, y * depth / 2, (i - (hspans - 1) / 2) * hspan]) *
rotate([y > 0 ? 180 : 0, x * y * 90]),
];
function side_holes(type) = [for(p = fixing_block_positions(type), q = fixing_block_holes(bbox_screw(type))) p * q];
module fixing_block_positions(type) {
t = sheet_thickness(bbox_sheets(type));
bt = sheet_thickness(bbox_base_sheet(type));
tt = sheet_thickness(bbox_top_sheet(type));
h = bbox_height(type) / 2 - 1;
for(p = fixing_block_positions(type))
let(z = transform([0, 0, 0], p).z, $thickness = z > h ? tt : z < -h ? bt : t)
multmatrix(p)
children();
}
module drill_holes(type, t)
for(list = [corner_holes(type), side_holes(type)], p = list)
let(q = t * p)
if(abs(transform([0, 0, 0], q).z) < eps)
multmatrix(q)
drill(screw_clearance_radius(bbox_screw(type)), 0);
module bbox_base_blank(type) { //! 2D template for the base
dxf("bbox_base");
difference() {
sheet_2D(bbox_base_sheet(type), bbox_width(type), bbox_depth(type), 1);
drill_holes(type, translate(bbox_height(type) / 2));
}
}
module bbox_top_blank(type) { //! 2D template for the top
dxf("bbox_top");
t = sheet_thickness(bbox_sheets(type));
difference() {
translate([0, t / 2])
sheet_2D(bbox_top_sheet(type), bbox_width(type) + 2 * t, bbox_depth(type) + t);
drill_holes(type, translate(-bbox_height(type) / 2));
}
}
module bbox_left_blank(type) { //! 2D template for the left side
dxf("bbox_left");
t = sheet_thickness(bbox_sheets(type));
bb = sheet_thickness(bbox_base_sheet(type));
difference() {
translate([-t / 2, -bb / 2])
sheet_2D(bbox_sheets(type), bbox_depth(type) + t, bbox_height(type) + bb);
drill_holes(type, rotate([0, 90, 90]) * translate([bbox_width(type) / 2, 0]));
}
}
module bbox_right_blank(type) { //! 2D template for the right side
dxf("bbox_right");
t = sheet_thickness(bbox_sheets(type));
bb = sheet_thickness(bbox_base_sheet(type));
difference() {
translate([t / 2, -bb / 2])
sheet_2D(bbox_sheets(type), bbox_depth(type) + t, bbox_height(type) + bb);
drill_holes(type, rotate([0, -90, 90]) * translate([-bbox_width(type) / 2, 0]));
}
}
module bbox_front_blank(type) { //! 2D template for the front
dxf("bbox_front");
t = sheet_thickness(bbox_sheets(type));
bb = sheet_thickness(bbox_base_sheet(type));
bt = sheet_thickness(bbox_top_sheet(type));
difference() {
translate([0, (bt - bb) / 2])
sheet_2D(bbox_sheets(type), bbox_width(type) + 2 * t, bbox_height(type) + bb + bt);
drill_holes(type, rotate([-90, 0, 0]) * translate([0, bbox_depth(type) / 2]));
}
}
module bbox_back_blank(type) { //! 2D template for the back
dxf("bbox_back");
bb = sheet_thickness(bbox_base_sheet(type));
t = sheet_thickness(bbox_sheets(type));
difference() {
translate([0, -bb / 2])
sheet_2D(bbox_sheets(type), bbox_width(type), bbox_height(type) + bb);
drill_holes(type, rotate([90, 0, 0]) * translate([0, -bbox_depth(type) / 2]));
}
}
module bbox_base(type) render_2D_sheet(bbox_base_sheet(type)) bbox_base_blank(type); //! Default base, can be overridden to customise
module bbox_top(type) render_2D_sheet(bbox_top_sheet(type)) bbox_top_blank(type); //! Default top, can be overridden to customise
module bbox_back(type) render_2D_sheet(bbox_sheets(type)) bbox_back_blank(type); //! Default back, can be overridden to customise
module bbox_front(type) render_2D_sheet(bbox_sheets(type)) bbox_front_blank(type); //! Default front, can be overridden to customise
module bbox_left(type) render_2D_sheet(bbox_sheets(type)) bbox_left_blank(type); //! Default left side, can be overridden to customise
module bbox_right(type) render_2D_sheet(bbox_sheets(type)) bbox_right_blank(type); //! Default right side, can be overridden to customise
module _bbox_assembly(type, top = true, base = true, left = true, right = true, back = true, front = true) //! The box assembly, wrap with a local copy without parameters
assembly("bbox") {
width = bbox_width(type);
depth = bbox_depth(type);
height = bbox_height(type);
echo("Box:", width, depth, height);
t = sheet_thickness(bbox_sheets(type));
bt = sheet_thickness(bbox_base_sheet(type));
tt = sheet_thickness(bbox_top_sheet(type));
corner_block_positions(type)
fastened_corner_block_assembly(t, bbox_screw(type), $thickness);
fixing_block_positions(type)
fastened_fixing_block_assembly(t, bbox_screw(type), thickness2 = $thickness);
for(x = [-1, 1])
translate([x * (width / 2 + t / 2 + eps + 25 * exploded()), 0])
rotate([90, 0, x * 90])
if(x > 0) {
if(right)
bbox_right(type);
}
else
if(left)
bbox_left(type);
for(y = [-1, 1])
translate([0, y * (depth / 2 + t / 2 + eps + 25 * exploded())])
rotate([90, 0, y * 90 + 90])
if(y < 0) {
if(front)
bbox_front(type);
}
else
if(back)
bbox_back(type);
for(z = [-1, 1]) {
sheet_thickness = z > 0 ? tt : bt;
translate_z(z * (height / 2 + sheet_thickness / 2 + eps + 100 * exploded()))
if(z > 0) {
if(top)
bbox_top(type);
}
else
if(base)
bbox_base(type);
}
}

187
printed/cable_grommets.scad Normal file
View File

@@ -0,0 +1,187 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Printed cable grommets for passing cables through panels avoiding sharp edges and in the case
//! of conductive panels, an extra layer of insulation.
//
include <../core.scad>
use <../vitamins/cable_strip.scad>
base = 1.25;
slot_height = round_to_layer(1.27) + layer_height;
wall = 1.6;
overlap = 1.5;
height = base + slot_height + wall + overlap;
rad = wall + overlap;
clearance = 0.1;
module ribbon_grommet_hole(ways, h = 50, expand = true) { //! Generate a hole for a ribbon grommet
length = ribbon_clamp_slot(ways) + 2 * wall;
rad = cnc_bit_r;
height = base + slot_height + wall;
extrude_if(h)
offset(expand ? clearance : 0)
hull() {
translate([-length / 2, 0])
square([length, base]);
for(end = [-1, 1])
translate([end * (length / 2 - rad), height - rad])
drill(rad, 0);
}
}
module ribbon_grommet(ways, thickness) { //! Generate the STL for a printed ribbon grommet
stl(str("ribbon_grommet_", ways, "_", thickness));
width = 2 * (wall + clearance) + thickness;
slot_length = ribbon_clamp_slot(ways);
length = slot_length + 2 * wall + 2 * overlap;
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(height = wall, center = true, convexity = 5)
difference() {
hull() {
translate([-length / 2, 0])
square([length, base]);
for(end = [-1, 1])
translate([end * (length / 2 - rad), height - rad])
semi_circle(rad);
}
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
linear_extrude(height = width -1, center = true)
difference() {
ribbon_grommet_hole(ways, expand = false, h = 0);
translate([-slot_length / 2, base])
square([slot_length, slot_height]);
}
}
}
module round_grommet_top(diameter, thickness, od = undef) { //! Generate the STL for a round grommet top half
stl(str("round_grommet_top_", round(diameter * 10), "_", thickness));
chamfer = layer_height;
h = wall + thickness + wall;
r1 = diameter / 2;
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
r3 = r2 + overlap;
r0 = r1 + 1;
union() {
rotate_extrude()
polygon([
[r0, 0],
[r3 - chamfer, 0],
[r3, chamfer],
[r3, wall],
[r2, wall],
[r2, h - chamfer],
[r2 - chamfer, h],
[r0, h],
]);
render() difference() {
cylinder(r = r0 + eps, h = h);
poly_cylinder(r = r1, h = 100, center = true);
}
}
}
module round_grommet_bottom(diameter, od = undef) { //! Generate the STL for a round grommet bottom half
stl(str("round_grommet_bottom_", round(diameter * 10)));
chamfer = layer_height;
r1 = diameter / 2;
r2 = od == undef ? corrected_radius(r1) + wall : od / 2;
r3 = r2 + max(overlap, wall + chamfer);
rotate_extrude()
polygon([
[r2, chamfer],
[r2 + chamfer, 0],
[r3, 0],
[r3, wall - chamfer],
[r3 - chamfer, wall],
[r2, wall],
]);
}
module round_grommet_hole(diameter, h = 100) //! Make a hole for a round grommet
drill(diameter / 2 + wall + clearance, h);
module round_grommet_assembly(diameter, thickness, od = undef) {
color(pp1_colour)
translate_z(wall)
vflip()
round_grommet_top(diameter, thickness, od);
color(pp2_colour)
translate_z(-thickness)
vflip()
round_grommet_bottom(diameter, od);
}
module mouse_grommet_hole(r, h = 50, z = undef, expand = wall + clearance) //! Make a hole for a mouse grommet
extrude_if(h)
hull(){
R = r + expand;
translate([0, z == undef ? R : z])
semi_circle(R);
translate([-R, 0])
square([2 * R, eps]);
}
module mouse_grommet(r, thickness) { //! Make the STL for a mouse grommet
stl(str("mouse_grommet_", r * 10, "_", thickness));
width = 2 * (wall + clearance) + thickness;
length = 2 * r + 2 * wall + 2 * overlap;
rotate([90, 0, 0])
union() {
for(side = [-1, 1])
translate_z(side * (width - wall) / 2)
linear_extrude(height = wall, center = true)
difference() {
mouse_grommet_hole(r + wall + overlap, z = r + wall, h = 0, expand = 0);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
linear_extrude(height = width - 1, center = true)
difference() {
mouse_grommet_hole(r, h = 0, z = r + wall, expand = wall);
translate([0, wall])
mouse_grommet_hole(r, h = 0, expand = 0);
}
}
}
module ribbon_grommet_20_3_stl() ribbon_grommet(20, 3);
module mouse_grommet_20_3_stl() mouse_grommet(2,3);
module mouse_grommet_30_3_stl() mouse_grommet(3,3);

63
printed/carriers.scad Normal file
View File

@@ -0,0 +1,63 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Adapts ESP12 module to 0.1" grid. See <https://hydraraptor.blogspot.com/2018/04/esp-12-module-breakout-adaptor.html>.
//
$extrusion_width = 0.5;
include <../core.scad>
module ESP12F_carrier_stl() { //! Generate the STL for an ESP12 carrier
stl("ESP12F_carrier");
pins = 8;
pitch1 = 2;
pitch2 = 2.54;
hole = pitch1 - squeezed_wall;
hole2 = pitch2 - 3 * extrusion_width;
length1 = (pins - 1) * pitch1 + hole + squeezed_wall * 2;
length2 = (pins - 1) * pitch2 + hole + squeezed_wall * 2;
height = 3;
wpitch1 = (pins - 1) * pitch1;
wpitch2 = ceil(wpitch1 / 2.54) * 2.54;
width1 = wpitch1 + hole + squeezed_wall * 2;
width2 = wpitch2 + hole2 + squeezed_wall * 2;
difference() {
hull() {
translate_z(height - eps / 2)
cube([width1, length1, eps], center = true);
translate_z(eps / 2)
cube([width2, length2, eps], center = true);
}
for(side = [-1, 1])
for(i = [0 : pins - 1])
hull() {
translate([side * wpitch1 / 2, i * pitch1 - (pins - 1) * pitch1 / 2, height])
cube([hole, hole, eps], center = true);
translate([side * wpitch2 / 2, i * pitch2 - (pins - 1) * pitch2 / 2])
cube([hole2, hole2, eps], center = true);
}
}
}

181
printed/corner_block.scad Normal file
View File

@@ -0,0 +1,181 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Corner brackets using threaded inserts for fastening three sheets together at right angles.
//! Defaults to M3 but other screws sizes can be specified provided they have inserts defined.
//!
//! See [butt_box](#Butt_box) for an example of usage.
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
use <../utils/rounded_cylinder.scad>
use <../utils/maths.scad>
def_screw = M3_cap_screw;
wall = 3;
overshoot = 2; // how far screw can overshoot the insert
function corner_block_screw() = def_screw; //! Default screw type
function corner_block_hole_offset(screw = def_screw) = //! Hole offset from the edge
let(insert = screw_insert(screw))
insert_length(insert) + max(overshoot + screw_clearance_radius(screw), insert_hole_radius(insert)) + 1;
function corner_block_width(screw = def_screw) = //! Block width, depth and height
corner_block_hole_offset(screw) + insert_outer_d(screw_insert(screw)) / 2 + wall;
function corner_block_v_hole(screw = def_screw) = let(offset = corner_block_hole_offset(screw)) translate([offset, offset]) * rotate([180, 0, 0]); //! Transform to bottom hole
function corner_block_h_holes(screw = def_screw) = //! List of transforms to side holes
let(offset = corner_block_hole_offset(screw))
[translate([offset, 0, offset]) * rotate([90, 0, 0]),
translate([0, offset, offset - layer_height]) * rotate([90, 0, -90])];
function corner_block_holes(screw) = concat([corner_block_v_hole(screw)], corner_block_h_holes(screw)); //! List of transforms to all holes
module corner_block_v_hole(screw = def_screw) //! Place children at the bottom screw hole
multmatrix(corner_block_v_hole(screw))
children();
module corner_block_h_holes(screw = def_screw) //! Place children at the side screw holes
for(p = corner_block_h_holes(screw))
multmatrix(p)
children();
module corner_block_holes(screw = def_screw) //! Place children at all the holes
for(p = corner_block_holes(screw))
multmatrix(p)
children();
module corner_block(screw = def_screw, name = false) { //! Generate the STL for a printed corner block
stl(name ? name : str("corner_block", "_M", screw_radius(screw) * 20));
r = 1;
cb_width = corner_block_width(screw);
cb_height = cb_width;
cb_depth = cb_width;
insert = screw_insert(screw);
corner_rad = insert_outer_d(insert) / 2 + wall;
offset = corner_block_hole_offset(screw);
difference() {
hull() {
translate([r, r])
rounded_cylinder(r = r, h = cb_height, r2 = r);
translate([r, cb_depth - r])
cylinder(r = r, h = cb_height - corner_rad);
translate([cb_width - r, r])
cylinder(r = r, h = cb_height - corner_rad);
translate([offset, offset, offset])
sphere(corner_rad);
translate([offset, offset])
cylinder(r = corner_rad, h = offset);
translate([offset, r, offset])
rotate([-90, 0, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
translate([r, offset, offset])
rotate([0, 90, 180])
rounded_cylinder(r = corner_rad, h = r, r2 = r);
}
corner_block_v_hole(screw)
insert_hole(insert, overshoot);
corner_block_h_holes(screw)
insert_hole(insert, overshoot, true);
children();
}
}
module corner_block_assembly(screw = def_screw, name = false) //! The printed block with inserts
assembly(str("corner_block_M", 20 * screw_radius(screw))) {
insert = screw_insert(screw);
color(name ? pp2_colour : pp1_colour)
render() corner_block(screw, name) children();
corner_block_h_holes(screw)
insert(insert);
corner_block_v_hole(screw)
insert(insert);
}
module fastened_corner_block_assembly(thickness, screw = def_screw, thickness_below = undef, name = false) { //! Printed block with all fasteners
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + insert_length(insert) + overshoot);
corner_block_assembly(screw, name) children();
corner_block_h_holes(screw)
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
thickness2 = thickness_below ? thickness_below : thickness;
screw_length2 = screw_shorter_than(2 * washer_thickness(washer) + thickness2 + insert_length(insert) + overshoot);
corner_block_v_hole(screw)
translate_z(thickness2)
screw_and_washer(screw, screw_length2, true);
}
module corner_block_M20_stl() corner_block(M2_cap_screw);
module corner_block_M25_stl() corner_block(M2p5_cap_screw);
module corner_block_M30_stl() corner_block(M3_cap_screw);
module corner_block_M40_stl() corner_block(M4_cap_screw);
//
//! 1. Lay the blocks out and place an M2 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M20_assembly() corner_block_assembly(M2_cap_screw);
//
//! 1. Lay the blocks out and place an M2.5 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M25_assembly() corner_block_assembly(M2p5_cap_screw);
//
//! 1. Lay the blocks out and place an M3 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M30_assembly() corner_block_assembly(M3_cap_screw);
//
//! 1. Lay the blocks out and place an M4 insert in each upward facing hole.
//! 1. Push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on each of their other two flat sides and repeat.
//
module corner_block_M40_assembly() corner_block_assembly(M4_cap_screw);

187
printed/door_hinge.scad Normal file
View File

@@ -0,0 +1,187 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Door hinges to hang an acrylic sheet door on a 3D printer, default 6mm thick.
//!
//! The screws are tapped into the acrylic.
//! Rubber door [sealing strip](#sealing_strip) is used to make it airtight and a [door_latch](#door_latch) holds it closed.
//
include <../core.scad>
include <../vitamins/screws.scad>
width = 18;
thickness = 4;
rad = 3;
dia = 12;
pin_screw = M3_cap_screw;
screw = M3_dome_screw;
stat_screw = M4_dome_screw;
stat_width = 15;
stat_length = 34;
stat_clearance = 0.75;
function door_hinge_pin_x() = -dia / 2; //! X offset of the hinge pin
function door_hinge_pin_y() = -dia / 2 - stat_clearance; //! Y offset of the hinge pin
function door_hinge_screw() = screw; //! Screw type used for hinge pin
function door_hinge_stat_screw() = stat_screw; //! Screw use to fasten the stationary part
function door_hinge_stat_width() = stat_width; //! Width of the stationary part
function door_hinge_stat_length() = stat_length; //! Length of the stationary part
module door_hinge_hole_positions(dir = 0) { //! Position chidren at the door hole positions
hole_pitch = width - 10;
for(side = [-1, 1])
translate([width / 2 + side * hole_pitch / 2, -dir * width / 2 -side * hole_pitch / 2])
children();
}
module door_hinge(door_thickness) { //! Generates STL for the moving part of the hinge
stl(str("door_hinge_", door_thickness));
hole_pitch = width - 10;
union() {
rotate([90, 0, 0])
linear_extrude(height = width, center = true)
difference() {
hull() {
translate([dia / 2, thickness + door_thickness / 2])
intersection() {
rotate(180)
teardrop(r = dia / 2, h = 0, truncate = false);
square([dia + 1, 2 * thickness + door_thickness], center = true);
}
square([1, thickness + door_thickness]);
}
translate([dia / 2, thickness + door_thickness / 2])
teardrop(r = screw_clearance_radius(pin_screw), h = 0);
}
linear_extrude(height = thickness)
difference() {
hull() {
translate([0, -width / 2])
square([1, width]);
for(side = [-1, 1])
translate([-width + rad, side * (width / 2 - rad)])
circle4n(rad);
}
rotate(180)
vflip()
door_hinge_hole_positions()
poly_circle(screw_clearance_radius(screw));
}
}
}
module door_hinge_6_stl() door_hinge(6);
module door_hinge_stat_hole_positions(dir = 0) { //! Position children over the screws holes of the stationary part
hole_pitch = dia + (stat_length - dia) / 2;
for(side = [-1, 1])
translate([side * hole_pitch / 2, dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw))), thickness])
children();
}
module door_hinge_stat_stl() { //! Generates the STL for the stationary part
stl("door_hinge_stat");
union() {
linear_extrude(height = thickness)
difference() {
rounded_square([stat_length, stat_width], rad);
door_hinge_stat_hole_positions()
poly_circle(screw_clearance_radius(stat_screw));
}
rotate([90, 0, 0])
linear_extrude(height = stat_width, center = true)
difference() {
hull() {
translate([0, dia / 2 + stat_clearance])
circle(d = dia);
translate([0, 0.5])
square([dia, 1], center = true);
}
translate([0, dia / 2 + stat_clearance])
teardrop(r = screw_clearance_radius(pin_screw), h = 0);
}
}
}
module door_hinge_assembly(top, door_thickness = 6) { //! The moving assembly that goes on the door
dir = top ? -1 : 1;
pin_x = door_hinge_pin_x();
pin_y = door_hinge_pin_y();
washer = screw_washer(screw);
screw_length = screw_shorter_than(thickness + door_thickness + washer_thickness(washer));
translate([0, pin_y - (thickness + door_thickness / 2), dir * width / 2]) {
rotate([90, 0, 180])
color("red") door_hinge(door_thickness);
rotate([90, 0, 0])
door_hinge_hole_positions()
screw_and_washer(screw, screw_length);
}
translate([pin_x, pin_y, top ? 0 : -washer_thickness(screw_washer(pin_screw))])
washer(screw_washer(pin_screw));
translate([pin_x, pin_y, top ? washer_thickness(screw_washer(pin_screw)) + stat_width : width])
screw_and_washer(pin_screw, screw_longer_than(2 * washer_thickness(screw_washer(pin_screw)) + width + stat_width));
}
module door_hinge_static_assembly(top, sheet_thickness = 3) { //! The stationary assembly
dir = top ? -1 : 1;
pin_x = door_hinge_pin_x();
stat_washer = screw_washer(stat_screw);
stat_nut = screw_nut(stat_screw);
stat_screw_length = screw_longer_than(thickness + sheet_thickness + 2 * washer_thickness(stat_washer) + nut_thickness(stat_nut, true));
translate([pin_x, 0, -dir * (stat_width / 2 + washer_thickness(screw_washer(pin_screw)))])
rotate([90, 0, 0]) {
color("lime") door_hinge_stat_stl();
door_hinge_stat_hole_positions() {
screw_and_washer(stat_screw, stat_screw_length);
translate_z(-thickness - sheet_thickness)
vflip()
nut_and_washer(stat_nut, true);
}
}
}
module door_hinge_parts_stl() { //! Generates the STL for both parts of the hinge
translate([2, width / 2 + 1])
door_hinge_6_stl();
translate([0, -stat_width / 2 - 1])
door_hinge_stat_stl();
}

81
printed/door_latch.scad Normal file
View File

@@ -0,0 +1,81 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Door latch for 6mm acrylic door for 3D printer. See [door_hinge](#door_hinge).
//
include <../core.scad>
use <../utils/hanging_hole.scad>
include <../vitamins/screws.scad>
length = 35;
width = 12;
height = 14.25;
thickness = 5;
rad = 3;
screw = M4_hex_screw;
function door_latch_screw() = screw; //! The screw used for the axle
function door_latch_offset() = width / 2 + 1; //! Offset of the axle from the door edge
nut_trap_depth = round_to_layer(screw_head_height(screw)) + 4 * layer_height;
module door_latch_stl() { //! Generates the STL for the printed part
stl("door_latch");
ridge = 4;
difference() {
union() {
hull() {
rounded_rectangle([length, width, thickness - tan(30) * (width - ridge) / 2], rad, center = false);
translate_z(thickness / 2)
cube([length, ridge, thickness], center = true);
}
cylinder(d = width, h = height);
}
hanging_hole(nut_trap_depth, screw_clearance_radius(screw))
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
}
module door_latch_assembly(sheet_thickness = 3) { //! The assembly for a specified sheet thickess
washer = screw_washer(screw);
nut = screw_nut(screw);
screw_length = screw_longer_than(height - nut_trap_depth + sheet_thickness + 2 * washer_thickness(washer) + nut_thickness(nut, true));
translate([0, -height - washer_thickness(washer)])
rotate([-90, 0, 0]) {
color("lime") render() door_latch_stl();
translate_z(nut_trap_depth)
vflip()
screw(screw, screw_length);
translate_z(height)
washer(washer);
translate_z(height + sheet_thickness + washer_thickness(washer))
nut_and_washer(nut, true);
}
}

92
printed/fan_guard.scad Normal file
View File

@@ -0,0 +1,92 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//! Pintable fan finger guard to match the specified fan. To be ```include```d, not ```use```d.
//!
//! The ring spacing as well as the number of spokes can be specified, if zero a gasket is generated instead of a guard.
//
use <../utils/tube.scad>
function fan_guard_thickness() = 2; //! Default thickness
function fan_guard_wall() = extrusion_width - layer_height / 2 + nozzle / 2 + extrusion_width / 2;
function fan_guard_corner_r(type) = washer_diameter(screw_washer(fan_screw(type))) / 2 + 0.5; //! Corner radius of the guard
function fan_guard_width(type) = max(2 * (fan_hole_pitch(type) + fan_guard_corner_r(type)), fan_bore(type) + 4 * fan_guard_wall()); //! Width of the guard
module fan_guard(type, name = false, thickness = fan_guard_thickness(), spokes = 4, finger_width = 7, grill = false) { //! Generate the STL
if(thickness)
stl(name ? name : str("fan_guard_", fan_width(type)));
hole_pitch = fan_hole_pitch(type);
corner_radius = fan_guard_corner_r(type);
wall = grill ? 2 : fan_guard_wall();
spoke = grill ? 3 : wall;
width = fan_guard_width(type);
hole = fan_aperture(type) / 2;
max_ring_pitch = finger_width + wall;
inner_ring = max_ring_pitch / 2;
gap = hole + wall / 2 - inner_ring;
rings = ceil(gap / max_ring_pitch);
ring_pitch = gap / rings;
spoke_end = grill && fan_aperture(type) > fan_bore(type) ? hole - ring_pitch : hole;
spoke_start = grill && rings > 1 ? inner_ring + ring_pitch : inner_ring;
rounding = grill ? 1.5 : 0;
extrude_if(thickness, center = false) {
difference() {
offset(-rounding) offset(rounding) {
difference() {
rounded_square([width, width], r = width / 2 - hole_pitch);
fan_holes(type, !grill, !grill, h = 0);
}
if(spokes) {
intersection() {
union() {
for(i = [(grill ? 1 : 0) : 1 : rings - 1]) {
r = inner_ring + i * ring_pitch;
ring(or = r + wall / 2, ir = r - wall / 2);
}
for(i = [0 : spokes - 1])
rotate(i * 360 / spokes + 45)
translate([spoke_start, -spoke / 2])
square([spoke_end - spoke_start + eps, spoke]);
}
square(width - eps, center = true);
}
}
}
if(grill)
fan_hole_positions(type, z = 0)
drill(screw_clearance_radius(fan_screw(type)), 0);
}
if(grill)
difference() {
r = min(inner_ring + ring_pitch, fan_hub(type) / 2);
circle(r);
for(a = [45 : 90 : 360])
rotate(a)
translate([r / 2, 0])
circle(wall);
}
}
}

170
printed/fixing_block.scad Normal file
View File

@@ -0,0 +1,170 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Fixing block to mount two sheets at right angles using threaded inserts.
//! Defaults to M3 but other screw sizes can be specified provided they have inserts defined.
//!
//! See [butt_box](#Butt_box) for an example of usage.
//!
//! Note that the block with its inserts is defined as a sub assembly, but its fasteners get added to the parent assembly.
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
use <../utils/maths.scad>
def_screw = M3_cap_screw;
wall = 2.5;
function fixing_block_screw() = def_screw; //! Default screw type
function fixing_block_width(screw = def_screw) = 4 * wall + 3 * insert_outer_d(screw_insert(screw)); //! Width given screw size
function fixing_block_depth(screw = def_screw) = //! Depth given screw size
let(insert = screw_insert(screw))
max(insert_length(insert) + wall, insert_outer_d(insert) + 2 * wall);
function fixing_block_height(screw = def_screw) = fixing_block_depth(screw); //! Height given screw size, same as depth
function fixing_block_h_hole(screw = def_screw) = translate(fixing_block_depth(screw) / 2) * rotate([90, 0, 0]); //! Returns transform to position the horizontal screw
function fixing_block_v_holes(screw = def_screw) = //! Returns a list of transforms to position the vertical screws
let(pitch = 2 * insert_outer_d(screw_insert(screw)) + 2 * wall, offset = fixing_block_depth(screw) / 2)
[for(end = [-1, 1]) translate([end * pitch / 2, offset]) * rotate([180, 0, 0])];
function fixing_block_holes(screw) = concat([fixing_block_h_hole(screw)], fixing_block_v_holes(screw)); //! Returns a list of transforms to position all the screws
module fixing_block_h_hole(screw = def_screw) //! Position children on the horizontal hole
multmatrix(fixing_block_h_hole(screw))
children();
module fixing_block_v_holes(screw = def_screw) //! Position children on the vertical holes
for(p = fixing_block_v_holes(screw))
multmatrix(p)
children();
module fixing_block_holes(screw = def_screw) //! Position children on all the holes
for(p = fixing_block_holes(screw))
multmatrix(p)
children();
module fixing_block_h_hole_2D(screw = def_screw) //! Position 2D child on the horizontal hole
translate([0, fixing_block_depth(screw) / 2])
children();
module fixing_block(screw = def_screw) { //! Generate the STL
stl(str("fixing_block_M", screw_radius(screw) * 20));
r = 1;
insert = screw_insert(screw);
corner_rad = insert_outer_d(insert) / 2 + wall;
fb_width = fixing_block_width(screw);
fb_height = fixing_block_height(screw);
fb_depth = fixing_block_depth(screw);
difference() {
union() {
linear_extrude(height = fb_height, convexity = 5)
difference() {
hull() {
for(side = [-1, 1]) {
translate([side * (fb_width / 2 - corner_rad), fb_depth - corner_rad])
circle4n(corner_rad);
translate([side * (fb_width / 2 - r), r])
circle4n(r);
}
}
fixing_block_v_holes(screw)
poly_circle(screw_clearance_radius(screw));
}
}
translate_z(fb_height)
fixing_block_v_holes(screw)
insert_hole(insert);
fixing_block_h_hole(screw)
insert_hole(insert, 10, true);
}
}
module fixing_block_assembly(screw = def_screw) pose([55, 180, 25], [0, 4.8, 4.8]) //! Printed part with the inserts inserted
assembly(str("fixing_block_M", 20 * screw_radius(screw))) {
translate_z(fixing_block_height(screw))
rotate([0, 180, 0])
color(pp1_colour) render() fixing_block(screw);
insert = screw_insert(screw);
fixing_block_v_holes(screw)
insert(insert);
fixing_block_h_hole(screw)
insert(insert);
}
module fastened_fixing_block_assembly(thickness, screw = def_screw, screw2 = undef, thickness2 = undef) { //! Assembly with fasteners in place
module fb_screw(screw, thickness) {
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_longer_than(2 * washer_thickness(washer) + thickness + insert_length(insert));
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}
no_pose() fixing_block_assembly(screw);
fixing_block_v_holes(screw)
fb_screw(screw, thickness2 ? thickness2 : thickness);
fixing_block_h_hole(screw)
fb_screw(screw2 ? screw2 : screw, thickness);
}
module fixing_block_M20_stl() fixing_block(M2_cap_screw);
module fixing_block_M25_stl() fixing_block(M2p5_cap_screw);
module fixing_block_M30_stl() fixing_block(M3_cap_screw);
module fixing_block_M40_stl() fixing_block(M4_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M2 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M20_assembly() fixing_block_assembly(M2_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M2.5 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M25_assembly() fixing_block_assembly(M2p5_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M3 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M30_assembly() fixing_block_assembly(M3_cap_screw);
//
//! 1. Lay the blocks out with the two larger holes facing upwards.
//! 1. Place two M4 inserts into the two vertical holes of each block and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//! When removing the iron it helps to twist it a little anti-clockwise to release it from the thread.
//! 1. Lay the blocks on their backs and insert a third insert the same way.
//
module fixing_block_M40_assembly() fixing_block_assembly(M4_cap_screw);

151
printed/foot.scad Normal file
View File

@@ -0,0 +1,151 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Customisable printed rubber feet for equipment cases. The insert variant is better for solid feet because
//! inserts don't grip well in rubber.
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
foot = [25, 12, 3, 2, M4_cap_screw, 10];
insert_foot = [20, 10, 0, 2, M3_cap_screw, 10];
function foot() = foot; //! Default foot used unless a list of parameters is passed
function insert_foot() = insert_foot; //! Default foot with insert
function foot_diameter(type = foot) = type[0]; //! Outside maximum diameter
function foot_height(type = foot) = type[1]; //! Total height
function foot_thickness(type = foot)= type[2]; //! Thickness under the screw
function foot_rad(type = foot) = type[3]; //! Rounded corner radius
function foot_screw(type = foot) = type[4]; //! Screw type
function foot_slant(type = foot) = type[5]; //! Taper angle
module foot(type = foot) { //! Generate STL
stl("foot");
h = foot_height(type);
t = foot_thickness(type);
r1 = washer_radius(screw_washer(foot_screw(type)));
r3 = foot_diameter(type) / 2;
r2 = r3 - h * tan(foot_slant(type));
r = foot_rad(type);
union() {
rotate_extrude(convexity = 3) {
hull() {
translate([r1, 0])
square([r3 - r1, eps]);
for(x = [r1 + r, r2 - r])
translate([x, h - r])
circle4n(r);
}
}
linear_extrude(height = t)
difference() {
circle(r1 + eps);
poly_circle( screw_clearance_radius(foot_screw(type)));
}
}
}
module foot_assembly(t = 0, type = foot) { //! Assembly with fasteners in place for specified sheet thickness
screw = foot_screw(type);
washer = screw_washer(screw);
nut = screw_nut(screw);
squeeze = 0.5;
screw_length = screw_longer_than(foot_thickness(type) + t + 2 * washer_thickness(washer) + nut_thickness(nut, true) - squeeze);
vflip() explode(15, true) {
color(pp4_colour) foot(type);
if(t)
explode(15, true)
translate_z(foot_thickness(type))
screw_and_washer(screw, screw_length);
}
if(t)
translate_z(t)
nut_and_washer(nut, true);
}
module insert_foot(type = insert_foot) { //! Generate STL for foot with insert
stl("insert_foot");
h = foot_height(type);
r3 = foot_diameter(type) / 2;
r2 = r3 - h * tan(foot_slant(type));
r = foot_rad(type);
insert = screw_insert(foot_screw(type));
h2 = insert_hole_length(insert);
r4 = insert_hole_radius(insert);
r5 = r4 + 1;
union() {
rotate_extrude() {
union() {
hull() {
translate([r5, 0]) {
square([r3 - r5, eps]);
square([eps, h]);
}
translate([r2 - r, h - r])
circle4n(r);
}
}
}
linear_extrude(height = h2 + eps)
difference() {
circle(r5 + eps);
poly_circle(r4);
}
translate_z(h2)
cylinder(r = r5 + eps, h = h - h2);
}
}
//
//! Place the insert in the bottom of the foot and push home with a soldering iron with a conical bit heated to 200&deg;C.
//
module insert_foot_assembly(type = insert_foot) //! Printed part with insert in place
assembly("insert_foot") {
screw = foot_screw(type);
insert = screw_insert(screw);
vflip()
color(pp1_colour) insert_foot(type);
translate_z(-foot_thickness(type))
insert(insert);
}
module fastened_insert_foot_assembly(t = 3, type = insert_foot) { //! Assembly with fasteners in place for specified sheet thickness
screw = foot_screw(type);
washer = screw_washer(screw);
insert = screw_insert(screw);
screw_length = screw_shorter_than(insert_length(insert) + t + 2 * washer_thickness(washer));
explode(-10) insert_foot_assembly(type);
translate_z(t)
screw_and_washer(screw, screw_length, true);
}

103
printed/handle.scad Normal file
View File

@@ -0,0 +1,103 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Printed handle that can be printed without needing support material due to its truncated teardrop profile.
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
dia = 18;
length = 90; // inside length
height = 30; // inside height
screw = M4_cap_screw;
insert = screw_insert(screw);
pitch = length + dia;
function handle_length() = pitch + dia; //! Outside length
function handle_width() = dia; //! The width, i.e. diameter
function handle_height() = height + dia; //! Total height
function handle_screw() = screw; //! The screw type
module handle_screw_positions() //! Position children at the screw positions
for(end = [-1, 1])
translate([end * pitch / 2, 0])
children();
module handle_holes(h = 100) //! Drills holes for the screws
handle_screw_positions()
drill(screw_clearance_radius(screw), h);
module handle_stl() { //! generate the STL
stl("handle");
module end(end)
translate([end * pitch / 2, 0])
rotate_extrude()
intersection() {
rotate(180)
teardrop(r = dia / 2, h = 0);
translate([0, - (dia + 1) / 2])
square([dia / 2 + 1, dia + 1]);
}
translate_z(dia / 2)
union() {
hull() {
end(-1);
end(1);
}
handle_screw_positions()
render() difference() {
h = height + dia / 2;
cylinder(d = dia, h = h);
translate_z(h)
insert_hole(insert, 6);
}
}
}
//
//! Place inserts in the bottom of the posts and push them home with a soldering iron with a conical bit heated to 200&deg;C.
//
module handle_assembly() pose([225, 0, 150], [0, 0, 14]) //! Printed part with inserts in place
assembly("handle") {
translate_z(handle_height())
color(pp1_colour) vflip() handle_stl();
handle_screw_positions()
vflip()
insert(insert);
}
module handle_fastened_assembly(thickness) { //! Assembly with fasteners in place
screw_length = screw_longer_than(thickness + insert_length(insert) + 2 * washer_thickness(screw_washer(screw)));
handle_assembly();
handle_screw_positions()
vflip()
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}

119
printed/ribbon_clamp.scad Normal file
View File

@@ -0,0 +1,119 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Clamp for ribbon cable and polypropylene strip.
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
use <../vitamins/cable_strip.scad>
wall = 2;
min_wall = 2 * extrusion_width;
screw = M3_cap_screw;
insert = screw_insert(screw);
screw_depth = insert_length(insert) + 1;
function ribbon_clamp_hole_pitch(ways) = ribbon_clamp_slot(ways) + 2 * min_wall + 2 * corrected_radius(insert_hole_radius(insert)); //! Hole pitch
function ribbon_clamp_width() = 2 * (insert_hole_radius(insert) + 2); //! Width
function ribbon_clamp_length(ways) = ribbon_clamp_hole_pitch(ways) + ribbon_clamp_width(); //! Length given ways
function ribbon_clamp_height() = screw_depth + 1; //! Height
module ribbon_clamp_hole_positions(ways, side = undef) //! Place children at hole positions
for(x = is_undef(side) ? [-1, 1] : side)
translate([x * ribbon_clamp_hole_pitch(ways) / 2, 0])
children();
module ribbon_clamp_holes(ways, h = 20) //! Drill screw holes
ribbon_clamp_hole_positions(ways)
drill(screw_clearance_radius(screw), h);
module ribbon_clamp(ways) { //! Generate STL for given number of ways
stl(str("ribbon_clamp_", ways));
pitch = ribbon_clamp_hole_pitch(ways);
d = ribbon_clamp_width();
h = ribbon_clamp_height();
t = h - ribbon_clamp_slot_depth() - wall;
difference() {
union() {
hull() {
translate_z(h - t / 2)
cube([ribbon_clamp_hole_pitch(ways), d, t], center = true);
translate_z(1)
cube([pitch, max(wall, d - 2 * (h - t)), 2], center = true);
}
ribbon_clamp_hole_positions(ways, -1)
cylinder(d = d, h = h);
ribbon_clamp_hole_positions(ways, 1)
cylinder(d = d, h = h);
}
translate_z(h)
cube([ribbon_clamp_slot(ways), d + 1, ribbon_clamp_slot_depth() * 2], center = true);
ribbon_clamp_hole_positions(ways)
translate_z(h)
rotate(22.5)
insert_hole(insert, screw_depth - insert_length(insert));
}
}
module ribbon_clamp_assembly(ways) pose([55, 180, 25]) //! Printed part with inserts in place
assembly(str("ribbon_clamp_", ways)) {
h = ribbon_clamp_height();
color(pp1_colour) render()
translate_z(h) vflip() ribbon_clamp(ways);
ribbon_clamp_hole_positions(ways)
vflip()
insert(insert);
}
module ribbon_clamp_fastened_assembly(ways, thickness, screw = screw) { //! Clamp with fasteners in place
tape_l = floor(ribbon_clamp_slot(ways));
tape_width = 25;
tape_thickness = 0.5;
vitamin(str(": Tape self amalgamating silicone ",tape_l," x 25mm"));
washer = screw_washer(screw);
screw_length = screw_shorter_than(2 * washer_thickness(washer) + thickness + screw_depth);
ribbon_clamp_assembly(ways);
color("red") translate_z(tape_thickness / 2)
cube([tape_l, tape_width, tape_thickness], center = true);
ribbon_clamp_hole_positions(ways)
vflip()
translate_z(thickness)
screw_and_washer(screw, screw_length, true);
}
module ribbon_clamp_20_stl() ribbon_clamp(20);
//! * Place inserts into the holes and press home with a soldering iron with a conical bit heated to 200&deg;C.
module ribbon_clamp_20_assembly() ribbon_clamp_assembly(20);

77
printed/screw_knob.scad Normal file
View File

@@ -0,0 +1,77 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Knob with embedded hex head screw.
//
include <../core.scad>
include <../vitamins/screws.scad>
use <../utils/hanging_hole.scad>
knob_wall = 2;
function knob_nut_trap_depth(screw) = round_to_layer(screw_head_height(screw));
knob_stem_h = 6;
knob_thickness = 4;
knob_r = 8;
knob_wave = 1;
knob_waves = 9;
knob_height = knob_stem_h + knob_thickness;
function knob_height() = knob_height;
module screw_knob(screw) { //! Generate the STL foe a knob to fit the specified hex screw
stl(str("screw_knob_M", screw_radius(screw) * 20));
knob_stem_r = nut_trap_radius(screw_nut(screw)) + knob_wall;
function wave(a) = knob_r + sin(a * knob_waves) * knob_wave;
union() {
render() difference() {
cylinder(r = knob_stem_r, h = knob_thickness + knob_stem_h);
hanging_hole(knob_nut_trap_depth(screw), screw_clearance_radius(screw))
rotate(45)
circle(r = nut_trap_radius(screw_nut(screw)), $fn = 6);
}
linear_extrude(height = knob_thickness, convexity = 3)
difference() {
polygon(points = [for(a = [0 : 359]) [wave(a) * sin(a), wave(a) * cos(a)]]);
circle(knob_stem_r - eps);
}
}
}
//! Place the screw through the printed part
module screw_knob_assembly(screw, length) //! Assembly with the screw in place
assembly(str("screw_knob_M", 20 * screw_radius(screw), "_", length)) {
translate_z(knob_height)
vflip()
color(pp1_colour) screw_knob(screw);
translate_z(knob_height - knob_nut_trap_depth(screw))
rotate(-45)
screw(screw, length);
}
module screw_knob_M30_stl() screw_knob(M3_hex_screw);
module screw_knob_M40_stl() screw_knob(M4_hex_screw);
module screw_knob_M30_16_assembly() screw_knob_assembly(M3_hex_screw, 16);
module screw_knob_M40_16_assembly() screw_knob_assembly(M4_hex_screw, 16);

127
printed/socket_box.scad Normal file
View File

@@ -0,0 +1,127 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! UK 13A socket and printed backbox with earth terminal for the panel it is mounted on.
//
include <../core.scad>
include <../vitamins/mains_sockets.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
include <../vitamins/ring_terminals.scad>
box_height = 19;
base_thickness = 2;
wall = 3.5;
cable_d = 7;
cable_z = cable_d / 2 + base_thickness + 1;
function cable_y(type) = -mains_socket_depth(type) / 2;
cable_x = 0;
earth = M3_ringterm;
earth_screw = ringterm_screw(earth);
height = base_thickness + box_height;
function socket_box_depth() = height; //! Outside depth of the backbox
module socket_box(type) { //! Generate STL of the backbox for the specified socket
stl(str("socket_box_",type[0]));
screw = mains_socket_screw(type);
screw_clearance_radius = screw_clearance_radius(screw);
insert = screw_insert(screw);
insert_length = insert_length(insert);
insert_boss = mains_socket_insert_boss(type);
insert_hole_radius = insert_hole_radius(insert);
difference() {
linear_extrude(height = height, convexity = 5)
face_plate(type);
difference() {
translate_z(base_thickness)
linear_extrude(height = height, convexity = 5)
offset(-wall) offset(1) face_plate(type);
for(side = [-1, 1])
hull()
for(x = [1, 2])
translate([side * mains_socket_pitch(type) / x, 0])
cylinder(d = insert_boss, h = 100);
}
//
// Socket holes
//
translate_z(height)
mains_socket_hole_positions(type) {
poly_cylinder(r = screw_clearance_radius, h = 2 * box_height, center = true);
poly_cylinder(r = insert_hole_radius, h = 2 * insert_length, center = true);
}
//
// Cable hole
//
translate([cable_x, cable_y(type), cable_z])
rotate([90, 0, 0])
teardrop_plus(r = cable_d / 2, h = 30);
}
}
module socket_box_MKLOGIC_stl() socket_box(MKLOGIC);
module socket_box_Contactum_stl() socket_box(Contactum);
module socket_box_assembly(type) //! The box with inserts fitted
assembly(str("socket_box_", type[0])) {
screw = mains_socket_screw(type);
insert = screw_insert(screw);
color("lime") render() socket_box(type);
mains_socket_hole_positions(type)
translate_z(height)
insert(insert);
}
//! * Place two inserts into the holes in the lugs and press them home with a soldering iron with a tapered bit heated to 200&deg;C.
module socket_box_MKLOGIC_assembly() socket_box_assembly(MKLOGIC);
module socket_box_fastened_assembly(type, thickness) { //! The socket and backbox on each side of the specified panel thickness
screw = mains_socket_screw(type);
insert = screw_insert(screw);
screw_length = screw_longer_than(mains_socket_height(type) + thickness + insert_length(insert));
explode(-50)
translate_z(-height - thickness)
socket_box_assembly(type);
explode(50, true) {
mains_socket(type);
mains_socket_hole_positions(type)
translate_z(mains_socket_height(type))
screw(screw, screw_length);
}
mains_socket_earth_position(type)
rotate(-90)
ring_terminal_assembly(earth, thickness);
}

189
printed/strap_handle.scad Normal file
View File

@@ -0,0 +1,189 @@
//
// NopSCADlib Copyright Chris Palmer 2018
// 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 <https://www.gnu.org/licenses/>.
//
//
//! Retracting strap handle. Print the strap with flexible filament. Shown with default dimensions but can
//! be fully customised by passing a list of properties.
//
include <../core.scad>
include <../vitamins/screws.scad>
include <../vitamins/inserts.scad>
strap = [18, 2, M3_pan_screw, 3, 25];
function strap() = strap;
wall = 2;
clearance = 0.5;
step = 0.3;
overlap = 3;
panel_clearance = 0.25;
counterbore = 1;
function strap_width(type = strap) = type[0]; //! Width of strap
function strap_thickness(type = strap) = type[1]; //! Thickness of strap
function strap_screw(type = strap) = type[2]; //! Screw type
function strap_panel(type = strap) = type[3]; //! Panel thickness
function strap_extension(type = strap) = type[4]; //! How much length of the strap that can pull out
function strap_insert(type) = screw_insert(strap_screw(type)); //! The insert type
function strap_key(type) = strap_panel(type) - panel_clearance;
function strap_height(type) = wall + max(insert_length(strap_insert(type)) - strap_key(type), strap_thickness(type) + clearance); //! Height of the ends
function strap_end_width(type = strap) = strap_width(type) + 2 * (wall + clearance); //! Width of the ends
function strap_boss_r(type) = wall + insert_hole_radius(strap_insert(type));
function strap_min_width(type) = (strap_width(type) - 2 * (strap_boss_r(type) + clearance)) / 2;
module strap_boss_shape(type)
hull() {
r = strap_boss_r(type);
circle4n(r);
translate([r / 2, 0])
rounded_square([r, 2 * r], r = 1);
}
module strap_screw_positions(length, type = strap) //! Place children at the screw positions
for(end = [-1, 1])
translate([end * (length / 2 - wall - 2 * clearance - strap_min_width(type) - strap_boss_r(type) - strap_extension(type) / 2), 0])
rotate(end * 90 + 90)
children();
module strap_holes(length, type = strap, h = 100) //! The panel cut outs
extrude_if(h)
strap_screw_positions(length, type)
offset(cnc_bit_r + 0.05)
offset(-step - cnc_bit_r)
strap_boss_shape(type);
module strap(length, type = strap) { //! Generate the STL for the rubber strap
stl("strap");
len = length - 2 * (wall + clearance);
w = strap_width(type);
linear_extrude(height = strap_thickness(type), convexity = 3)
difference() {
rounded_square([len, w], w / 2 - eps);
for(end = [-1, 1])
translate([end * (len / 2 - strap_min_width(type) - strap_boss_r(type) - clearance), 0])
rotate(end * 90 + 90)
hull() {
offset(clearance)
strap_boss_shape(type);
translate([strap_extension(type) / 2, 0])
offset(clearance)
strap_boss_shape(type);
}
}
}
module strap_end(type = strap) { //! Generate the STL for end piece
stl("strap_end");
z1 = strap_height(type) - strap_thickness(type) - clearance;
z2 = strap_height(type) + strap_key(type);
r1 = strap_boss_r(type) - 1;
module outer()
hull() {
translate([0, -strap_end_width(type) / 2])
square([strap_boss_r(type) + overlap, strap_end_width(type)]);
translate([-strap_extension(type) / 2, 0])
circle(d = strap_end_width(type));
}
module with_hole()
difference() {
children();
circle(r1);
}
union() {
linear_extrude(height = z1)
with_hole()
outer();
translate_z(z1)
linear_extrude(height = strap_height(type) - z1)
difference() {
outer();
hull() {
translate([0, -strap_width(type) / 2 - clearance])
square([strap_boss_r(type) + overlap, strap_width(type) + 2 * clearance]);
translate([-strap_extension(type) / 2, 0])
circle(d = strap_width(type) + 2 * clearance);
}
}
linear_extrude(height = strap_height(type) - layer_height)
with_hole()
strap_boss_shape(type);
linear_extrude(height = z2)
with_hole()
offset(cnc_bit_r)
offset(-step - cnc_bit_r)
strap_boss_shape(type);
render() difference() {
cylinder(r = r1 + eps, h = z2);
translate_z(z2)
insert_hole(strap_insert(type), counterbore);
}
}
}
//
//! * Place the insert into the hole and push home with a soldering iron with a tapered bit heated to 200&deg;C.
//
module strap_end_assembly(type = strap)
assembly("strap_end") {
color(pp1_colour)
strap_end(type);
translate_z(strap_height(type) + strap_key(type))
insert(strap_insert(type));
}
module strap_assembly(length, type = strap) { //! Assembly with screws in place
screw = strap_screw(type);
washer = screw_washer(screw);
penny = penny_washer(washer);
insert = strap_insert(type);
screw_length = screw_shorter_than(washer_thickness(washer) + washer_thickness(penny) + insert_length(insert) + panel_clearance + counterbore);
color(pp4_colour) strap(length, type);
strap_screw_positions(length, type)
translate_z(strap_height(type))
vflip() {
explode(-50) strap_end_assembly(type);
translate_z(strap_height(type) + strap_panel(type))
screw_and_washer(screw, screw_length, true, true);
}
}