diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0bee55 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*_canute.bat +Thumbs.db +__pycache__ +*.pyc +tests/bom/ +tests/deps/ +*.log +*.html diff --git a/box.scad b/box.scad new file mode 100644 index 0000000..48b8def --- /dev/null +++ b/box.scad @@ -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 . +// + +// +//! 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 +use +use +use + +include +use + +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 diff --git a/box_assembly.scad b/box_assembly.scad new file mode 100644 index 0000000..9618f9e --- /dev/null +++ b/box_assembly.scad @@ -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 . +// + +// +// 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); + } +} diff --git a/butt_box.scad b/butt_box.scad new file mode 100644 index 0000000..d473b73 --- /dev/null +++ b/butt_box.scad @@ -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 . +// + +// +//! 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 +use +use + +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); + } +} diff --git a/cable_grommets.scad b/cable_grommets.scad new file mode 100644 index 0000000..ac2366c --- /dev/null +++ b/cable_grommets.scad @@ -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 . +// + +// +//! Printed cable grommets for passing cables through panels avoiding sharp edges and in the case +//! of conductive panels, an extra layer of insulation. +// +include +use + +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); diff --git a/carriers.scad b/carriers.scad new file mode 100644 index 0000000..f0c914a --- /dev/null +++ b/carriers.scad @@ -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 . +// + +// +//! Adapts ESP12 module to 0.1" grid. See . +// +$extrusion_width = 0.5; + +include + +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); + } + } +} diff --git a/core.scad b/core.scad new file mode 100644 index 0000000..57b7b1d --- /dev/null +++ b/core.scad @@ -0,0 +1,27 @@ +// +// 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 . +// + +// +// Include this file to use the library +// +include +// +// Global functions and modules +// +use diff --git a/corner_block.scad b/corner_block.scad new file mode 100644 index 0000000..ffb1808 --- /dev/null +++ b/corner_block.scad @@ -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 . +// + +// +//! 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 +include +include +use +use + +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°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°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°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°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); diff --git a/door_hinge.scad b/door_hinge.scad new file mode 100644 index 0000000..060a22e --- /dev/null +++ b/door_hinge.scad @@ -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 . +// + +// +//! 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 +include + +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(); +} diff --git a/door_latch.scad b/door_latch.scad new file mode 100644 index 0000000..79e43d4 --- /dev/null +++ b/door_latch.scad @@ -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 . +// + +// +//! Door latch for 6mm acrylic door for 3D printer. See [door_hinge](#door_hinge). +// +include +use +include + +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); + } +} diff --git a/fan_guard.scad b/fan_guard.scad new file mode 100644 index 0000000..7fc10fc --- /dev/null +++ b/fan_guard.scad @@ -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 . + +// +//! 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 + +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) { + 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); + } + } +} diff --git a/fixing_block.scad b/fixing_block.scad new file mode 100644 index 0000000..4f11d44 --- /dev/null +++ b/fixing_block.scad @@ -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 . +// + +// +//! 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 +include +include +use + +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°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°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°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°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); diff --git a/foot.scad b/foot.scad new file mode 100644 index 0000000..536587d --- /dev/null +++ b/foot.scad @@ -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 . +// + +// +//! Customisable printed rubber feet for equipment cases. The insert variant is better for solid feet because +//! inserts don't grip well in rubber. +// +include +include +include + +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°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); +} diff --git a/global_defs.scad b/global_defs.scad new file mode 100644 index 0000000..1d015fd --- /dev/null +++ b/global_defs.scad @@ -0,0 +1,90 @@ +// +// 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 . +// + +// +// This file included directly or indirectly in every scad file. +// +// This scheme allows the following: +// bom defaults to 0 +// Setting $bom on the command line or in the main file before including lib.scad overrides it everywhere. +// Setting $bom after including lib overrides bom in the libs but not in the local file. +// Setting $_bom in the local file overrides it in the local file but not in the libs. +// +//function is_undef(x) = x == undef; + +$_bom = is_undef($bom) ? 0 : $bom; // 0 no bom, 1 assemblies and stls, 2 vitamins as well +$exploded = is_undef($explode) ? 0 : $explode; // 1 for exploded view +layer_height = is_undef($layer_height) ? 0.25 : $layer_height; // layer heigth when printing +extrusion_width = is_undef($extrusion_width) ? 0.5 : $extrusion_width; // filament width when printing +nozzle = is_undef($nozzle) ? 0.45 : $nozzle; // 3D printer nozzle +cnc_bit_r = is_undef($cnc_bit_r) ? 1.2 : $cnc_bit_r; // miniumum tool radius when milling 2D objects +pp1_colour = is_undef($pp1_colour) ? "lime" : $pp1_colour; // printed part colour 1 +pp2_colour = is_undef($pp2_colour) ? "red" : $pp2_colour; // printed part colour 2 +pp3_colour = is_undef($pp3_colour) ? "blue" : $pp3_colour; // printed part colour 3 +pp4_colour = is_undef($pp4_colour) ? "darkorange" : $pp4_colour;// printed part colour 4 +show_rays = is_undef($show_rays) ? false : $show_rays; // show camera sight lines and light direction + +// Minimum wall is about two filaments wide but we extrude it closer to get better bonding +squeezed_wall = $preview ? 2 * extrusion_width - layer_height * (1 - PI / 4) + : extrusion_width - layer_height / 2 + nozzle / 2 + extrusion_width / 2; + +inf = 1e10; // very big +eps = 1/128; // small fudge factor to stop CSG barfing on coincident faces. +$fa = 6; +$fs = extrusion_width / 2; + +function round_to_layer(z) = ceil(z / layer_height) * layer_height; +// Some additional named colors +grey20 = [0.2, 0.2, 0.2]; +grey30 = [0.3, 0.3, 0.3]; +grey40 = [0.4, 0.4, 0.4]; +grey50 = [0.5, 0.5, 0.5]; +grey60 = [0.6, 0.6, 0.6]; +grey70 = [0.7, 0.7, 0.7]; +grey80 = [0.8, 0.8, 0.8]; +grey90 = [0.9, 0.9, 0.9]; +brass = "gold"; + +/* + * Enums + */ +// +// Screws +// +hs_cap = 0; +hs_pan = 1; +hs_cs = 2; // counter sunk +hs_hex = 3; +hs_grub = 4; // pulley set screw +hs_cs_cap = 5; +hs_dome = 6; +// +// Hot end descriptions +// +jhead = 1; +e3d = 2; +// +// Face enumeration +// +f_bottom = 0; +f_top = 1; +f_left = 2; +f_right = 3; +f_front = 4; +f_back = 5; diff --git a/handle.scad b/handle.scad new file mode 100644 index 0000000..aa295d2 --- /dev/null +++ b/handle.scad @@ -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 . +// + +// +//! Printed handle that can be printed without needing support material due to its truncated teardrop profile. +// +include +include +include + +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°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); +} diff --git a/lib.scad b/lib.scad new file mode 100644 index 0000000..05f6efc --- /dev/null +++ b/lib.scad @@ -0,0 +1,89 @@ +// +// 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 . +// + +// +// Include this file to use the library +// +include + +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include +include + +use +use +use + +use +use +use +use +use +use +use + +use +use +use +use +use +use +use +use +use +use +use +use +use +use diff --git a/libtest.scad b/libtest.scad new file mode 100644 index 0000000..436e15b --- /dev/null +++ b/libtest.scad @@ -0,0 +1,339 @@ +// +// 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 . +// + +// +// This file shows all the parts in the library. +// +include + +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use + +use +use +use +use +use +use +use +use +use +use +use +use +use +use +use + +x5 = 800; + +cable_grommets_y = 0; + +translate([x5, cable_grommets_y]) + cable_grommets(); + +translate([x5, cable_grommets_y + 50]) + feet(); + +translate([x5, cable_grommets_y + 75]) + fixing_blocks(); + +translate([x5, cable_grommets_y + 100]) + corner_blocks(); + +translate([x5, cable_grommets_y + 150]) + ribbon_clamps(); + +translate([x5 + 70, cable_grommets_y + 150]) + screw_knobs(); + +translate([x5, cable_grommets_y + 470]) { + door_hinges() + door_latches(); +} + +translate([x5, cable_grommets_y + 370]) + no_explode() socket_boxes(); + +translate([x5 + 60, cable_grommets_y + 200]) + strap_handles(); + +translate([x5, cable_grommets_y + 250]) + handle(); + +translate([900, 600]) + box_test(); + +translate([850, 1170]) + bbox_test(); + +x0 = 0; +inserts_y = 0; +nuts_y = inserts_y + 20; +washers_y = nuts_y + 60; +screws_y = washers_y + 120; +o_rings_y = screws_y + 130; +springs_y = o_rings_y + 20; +sealing_strip_y = springs_y + 20; +tubings_y = sealing_strip_y + 20; +pillars_y = tubings_y + 20; +leadnuts_y = pillars_y + 40; +pulleys_y = leadnuts_y +40; +hot_ends_y = pulleys_y + 60; +linear_bearings_y = hot_ends_y + 50; +sheets_y = linear_bearings_y + 50; +pcbs_y = sheets_y + 40; +displays_y = pcbs_y + 150; +fans_y = displays_y + 100; +transformers_y = fans_y + 120; +psus_y = transformers_y + 190; + +translate([x0 + 20, inserts_y]) + inserts(); + +translate([x0, inserts_y]) + ring_terminals(); + +translate([x0, nuts_y]) + nuts(); + +translate([x0, washers_y]) + washers(); + +translate([x0, screws_y]) + screws(); + +translate([x0, o_rings_y]) + o_rings(); + +translate([x0, springs_y]) + springs(); + +translate([x0 + 50, sealing_strip_y]) + sealing_strip_test(); + +translate([x0, tubings_y]) + tubings(); + +translate([x0, pillars_y]) + pillars(); + +translate([x0, leadnuts_y ]) + leadnuts(); + +translate([x0 + 80, leadnuts_y]) + ball_bearings(); + +translate([x0, pulleys_y]) + pulleys(); + +translate([x0, linear_bearings_y]) { + linear_bearings(); + rods(); +} + +translate([x0 + 10, hot_ends_y]) + hot_ends(); + +translate([x0, sheets_y]) + sheets(); + +translate([x0, pcbs_y]) + pcbs(); + +translate([x0, displays_y]) + displays(); + +translate([x0, fans_y]) { + fans(); + + translate_z(3) + fan_guards(); +} + +translate([x0, transformers_y]) + variacs(); + +translate([x0, psus_y]) + psus(); + + +x1 = x0 + 100; +zipties_y = 0; +bulldogs_y = zipties_y + 40; + +translate([x1, zipties_y]) + zipties(); + +translate([x1, bulldogs_y]) + bulldogs(); + +x2 = x1 + 90; +leds_y = 0; +carriers_y = leds_y + 40; +spades_y = carriers_y + 40; +buttons_y = spades_y + 40; +jacks_y = buttons_y + 40; +microswitches_y = jacks_y + 40; +rockers_y = microswitches_y + 40; +toggles_y = rockers_y + 40; +components_y = toggles_y + 40; + +translate([x2, leds_y]) + leds(); + +translate([x2 + 8, carriers_y]) + carriers(); + +translate([x2+ 38, carriers_y]) + meters(); + +translate([x2 + 68, carriers_y]) + fuseholders(); + +translate([x2, spades_y]) + spades(); + +translate([x2, buttons_y]) + buttons(); + +translate([x2, jacks_y]) + jacks(); + +translate([x2, microswitches_y]) + microswitches(); + +translate([x2, rockers_y]) + rockers(); + +translate([x2, toggles_y]) + toggles(); + +translate([x2, components_y]) + components(); + + +x3 = x2 + 150; +veroboard_y = 0; +d_connectors_y = veroboard_y + 110; +iecs_y = d_connectors_y + 80; +modules_y = iecs_y + 60; +ssrs_y = modules_y + 80; +blowers_y = ssrs_y + 60; +batteries_y = blowers_y + 100; +steppers_y = batteries_y + 70; + +translate([x3, veroboard_y]) + veroboard_test(); + +translate([x3, d_connectors_y]) + d_connectors(); + +translate([x3, iecs_y]) + iecs(); + +translate([x3 + 15, modules_y]) + microview(); + +translate([x3 + 40, modules_y]) + modules(); + +translate([x3, ssrs_y]) + ssrs(); + +translate([x3, blowers_y]) + blowers(); + +translate([x3, batteries_y]) + batteries(); + +translate([x2, steppers_y]) // interloper + stepper_motors(); + +translate([x3, transformers_y]) + transformers(); + + +x4 = x3 + 220; +belts_y = 0; +rails_y = belts_y + 200; +cable_strips_y = rails_y + 300; + +translate([x4 + 112, belts_y + 58]) { + belt_test(); + + translate([0, 60]) + opengrab_test(); +} + +translate([x4, rails_y + 130]) + rails(); + +translate([x4, cable_strips_y]) + cable_strips(); + +x6 = x5 + 150; +translate([x6, 125]) + light_strips(); diff --git a/ribbon_clamp.scad b/ribbon_clamp.scad new file mode 100644 index 0000000..e8aa642 --- /dev/null +++ b/ribbon_clamp.scad @@ -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 . +// + +// +//! Clamp for ribbon cable and polypropylene strip. +// +include +include +include +use + +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°C. +module ribbon_clamp_20_assembly() ribbon_clamp_assembly(20); diff --git a/screw_knob.scad b/screw_knob.scad new file mode 100644 index 0000000..d140eb5 --- /dev/null +++ b/screw_knob.scad @@ -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 . +// + +// +//! Knob with embedded hex head screw. +// +include +include +use + +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); diff --git a/scripts/blurb.py b/scripts/blurb.py new file mode 100644 index 0000000..73c8787 --- /dev/null +++ b/scripts/blurb.py @@ -0,0 +1,80 @@ +# +# 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 . +# +""" +Capture Markup lines in OpenSCAD source code denoted by '//!'. +""" +import re + +def parse_line(line): + """ process a line, add blurb to text and return true if got to a module or function """ + if line[:3] == '//!': + line = line.replace('~\n', ' \n') + start = 4 if line[3] == ' ' else 3 + return False, line[start :] + else: + words = line.split() + return len(words) and (words[0] == "module" or words[0] == "function"), "" + +def _scrape_blurb(lines): + """ Find Markup lines before the first function or module given a list of lines.""" + text = "" + for line in lines: + b, t = parse_line(line) + if b: + break + text += t + if len(text): + text += '\n' + return text + +def scrape_blurb(scad_file): + """ Find Markup lines before the first function or module.""" + with open(scad_file, "rt") as file: + lines = file.readlines() + return _scrape_blurb(lines) + +def scrape_module_blurb(lines): + """ Find the Markup lines before the last function or module. """ + text = "" + for line in lines: + b, t = parse_line(line) + text = "" if b else text + t + return text + +def scrape_code(scad_file): + """ Find the Markup lines on the first line of functions and modules. """ + with open(scad_file, "rt") as file: + lines = file.readlines() + blurb = _scrape_blurb(lines) + properties = {} + functions = {} + modules = {} + for line in lines: + match = re.match(r'^function (.*\(type\)|.*\(type ?= ?.*?\)) *= *type\[.*\].*?(?://! ?(.*))?$', line) + if match: + properties[match.group(1)] = match.group(2) + else: + match = re.match(r'^function (.*?\(.*?\)).*?(?://! ?(.*))$', line) + if match: + functions[match.group(1)] = match.group(2) + match = re.match(r'^module (.*?\(.*?\)).*?(?://! ?(.*))$', line) + if match: + modules[match.group(1)] = match.group(2) + + return { "blurb" : blurb, "properties" : properties, "functions" : functions, "modules": modules} diff --git a/scripts/bom.py b/scripts/bom.py new file mode 100644 index 0000000..1b79b36 --- /dev/null +++ b/scripts/bom.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function + +import os +import sys +import shutil +import openscad +from time import * +from set_config import * +import json + +def find_scad_file(mname): + for filename in os.listdir(source_dir): + if filename[-5:] == ".scad": + # + # look for module which makes the assembly + # + with open(source_dir + "/" + filename, "r") as f: + for line in f.readlines(): + words = line.split() + if len(words) and words[0] == "module": + module = words[1].split('(')[0] + if module == mname: + return filename + return None + +class BOM: + def __init__(self, name): + self.name = name + self.count = 1 + self.vitamins = {} + self.printed = {} + self.routed = {} + self.assemblies = {} + + def data(self, main): + return { + "name" : self.name, + "count" : self.count, + "assemblies" : [main.assemblies[ass].data(main) for ass in self.assemblies], + "vitamins" : self.vitamins, + "printed" : self.printed, + "routed" : self.routed + } + + def flat_data(self): + assemblies = {} + for ass in self.assemblies: + assemblies[ass] = self.assemblies[ass].count + return { + "assemblies" : assemblies, + "vitamins" : self.vitamins, + "printed" : self.printed, + "routed" : self.routed + } + + def add_part(self, s): + if s[-4:] == ".stl": + parts = self.printed + else: + if s[-4:] == ".dxf": + parts = self.routed + else: + parts = self.vitamins + if s in parts: + parts[s] += 1 + else: + parts[s] = 1 + + def add_assembly(self, ass): + if ass in self.assemblies: + self.assemblies[ass].count += 1 + else: + self.assemblies[ass] = BOM(ass) + + def make_name(self, ass): + if self.count == 1: + return ass + return ass.replace("assembly", "assemblies") + + def print_bom(self, breakdown, file = None): + if self.vitamins: + print("Vitamins:", file=file) + if breakdown: + longest = 0 + for ass in self.assemblies: + name = ass.replace("_assembly","") + longest = max(longest, len(name)) + for i in range(longest): + line = "" + for ass in sorted(self.assemblies): + name = ass.replace("_assembly","").replace("_"," ").capitalize() + index = i - (longest - len(name)) + if index < 0: + line += " " + else: + line += (" %s " % name[index]) + print(line[:-1], file=file) + + for part in sorted(self.vitamins): + if ': ' in part: + part_no, description = part.split(': ') + else: + part_no, description = "", part + if breakdown: + for ass in sorted(self.assemblies): + bom = self.assemblies[ass] + if part in bom.vitamins: + file.write("%2d|" % bom.vitamins[part]) + else: + file.write(" |") + print("%3d" % self.vitamins[part], description, file=file) + + if self.printed: + if self.vitamins: + print(file=file) + print("Printed:", file=file) + for part in sorted(self.printed): + if breakdown: + for ass in sorted(self.assemblies): + bom = self.assemblies[ass] + if part in bom.printed: + file.write("%2d|" % bom.printed[part]) + else: + file.write(" |") + print("%3d" % self.printed[part], part, file=file) + + if self.routed: + print(file=file) + print("CNC cut:", file=file) + for part in sorted(self.routed): + if breakdown: + for ass in sorted(self.assemblies): + bom = self.assemblies[ass] + if part in bom.routed: + file.write("%2d|" % bom.routed[part]) + else: + file.write(" |") + print("%3d" % self.routed[part], part, file=file) + + if self.assemblies: + print(file=file) + print("Assemblies:", file=file) + for ass in sorted(self.assemblies): + print("%3d %s" % (self.assemblies[ass].count, self.assemblies[ass].make_name(ass)), file=file) + +def parse_bom(file = "openscad.log", name = None): + main = BOM(name) + stack = [] + + for line in open(file): + pos = line.find('ECHO: "~') + if pos > -1: + s = line[pos + 8 : line.rfind('"')] + if s[-1] == '{': + ass = s[:-1] + if stack: + main.assemblies[stack[-1]].add_assembly(ass) #add to nested BOM + stack.append(ass) + main.add_assembly(ass) #add to flat BOM + else: + if s[0] == '}': + if s[1:] != stack[-1]: + raise Exception("Mismatched assembly " + s[1:] + str(stack)) + stack.pop() + else: + main.add_part(s) + if stack: + main.assemblies[stack[-1]].add_part(s) + return main + +def boms(target = None, assembly = None): + bom_dir = set_config(target) + "bom" + if assembly: + bom_dir += "/accessories" + if not os.path.isdir(bom_dir): + os.makedirs(bom_dir) + else: + assembly = "main_assembly" + if os.path.isdir(bom_dir): + shutil.rmtree(bom_dir) + sleep(0.1) + os.makedirs(bom_dir) + # + # Find the scad file that makes the module + # + scad_file = find_scad_file(assembly) + if not scad_file: + raise Exception("can't find source for " + assembly) + # + # make a file to use the module + # + bom_maker_name = source_dir + "/bom.scad" + with open(bom_maker_name, "w") as f: + f.write("use <%s>\n" % scad_file) + f.write("%s();\n" % assembly); + # + # Run openscad + # + openscad.run("-D","$bom=2","-D","$preview=true","-o", "openscad.echo", bom_maker_name) + os.remove(bom_maker_name) + print("Generating bom ...", end=" ") + + main = parse_bom("openscad.echo", assembly) + + if assembly == "main_assembly": + main.print_bom(True, open(bom_dir + "/bom.txt","wt")) + + for ass in sorted(main.assemblies): + with open(bom_dir + "/" + ass + ".txt", "wt") as f: + bom = main.assemblies[ass] + print(bom.make_name(ass) + ":", file=f) + bom.print_bom(False, f) + + with open(bom_dir + "/bom.json", 'w') as outfile: + json.dump(main.assemblies[assembly].data(main), outfile, indent = 4) + + print("done") + +if __name__ == '__main__': + args = len(sys.argv) + if args > 1: + if args > 2: + boms(sys.argv[1], sys.argv[2]) + else: + boms(sys.argv[1]) + else: + boms(); diff --git a/scripts/c14n_stl.py b/scripts/c14n_stl.py new file mode 100644 index 0000000..89cb8ff --- /dev/null +++ b/scripts/c14n_stl.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# +# 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 . +# + +# +# OpenSCAD produces randomly ordered STL files so source control like GIT can't tell if they have changed or not. +# This scrip orders each triangle to start with the lowest vertex first (comparing x, then y, then z) +# It then sorts the triangles to start with the one with the lowest vertices first (comparing first vertex, second, then third) +# This has no effect on the model but makes the STL consistent. I.e. it makes a canonical form. +# + +from __future__ import print_function + +import sys + +def cmz(x): + ''' Convert "-0" to "0". ''' + return '0' if x == '-0' else x + +class Vertex: + def __init__(self, x, y, z): + self.x, self.y, self.z = x, y, z + self.key = (float(x), float(y), float(z)) + +class Normal: + def __init__(self, dx, dy, dz): + self.dx, self.dy, self.dz = dx, dy, dz + +class Facet: + def __init__(self, normal, v1, v2, v3): + self.normal = normal + if v1.key < v2.key: + if v1.key < v3.key: + self.vertices = (v1, v2, v3) #v1 is the smallest + else: + self.vertices = (v3, v1, v2) #v3 is the smallest + else: + if v2.key < v3.key: + self.vertices = (v2, v3, v1) #v2 is the smallest + else: + self.vertices = (v3, v1, v2) #v3 is the smallest + + def key(self): + return (self.vertices[0].x, self.vertices[0].y, self.vertices[0].z, + self.vertices[1].x, self.vertices[1].y, self.vertices[1].z, + self.vertices[2].x, self.vertices[2].y, self.vertices[2].z) + +class STL: + def __init__(self, fname): + self.facets = [] + + with open(fname) as f: + words = [cmz(s.strip()) for s in f.read().split()] + + if words[0] == 'solid' and words[1] == 'OpenSCAD_Model': + i = 2 + while words[i] == 'facet': + norm = Normal(words[i + 2], words[i + 3], words[i + 4]) + v1 = Vertex(words[i + 8], words[i + 9], words[i + 10]) + v2 = Vertex(words[i + 12], words[i + 13], words[i + 14]) + v3 = Vertex(words[i + 16], words[i + 17], words[i + 18]) + i += 21 + self.facets.append(Facet(norm, v1, v2, v3)) + + self.facets.sort(key = Facet.key) + else: + print("Not an OpenSCAD ascii STL file") + sys.exit(1) + + def write(self, fname): + with open(fname,"wt") as f: + print('solid OpenSCAD_Model', file=f) + for facet in self.facets: + print(' facet normal %s %s %s' % (facet.normal.dx, facet.normal.dy, facet.normal.dz), file=f) + print(' outer loop', file=f) + for vertex in facet.vertices: + print(' vertex %s %s %s' % (vertex.x, vertex.y, vertex.z), file=f) + print(' endloop', file=f) + print(' endfacet', file=f) + print('endsolid OpenSCAD_Model', file=f) + +def canonicalise(fname): + stl = STL(fname) + stl.write(fname) + +if __name__ == '__main__': + if len(sys.argv) == 2: + canonicalise(sys.argv[1]) + else: + print("usage: c14n_stl file") + sys.exit(1) diff --git a/scripts/deps.py b/scripts/deps.py new file mode 100644 index 0000000..cd0ec69 --- /dev/null +++ b/scripts/deps.py @@ -0,0 +1,49 @@ +# +# 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 . +# +import os + +def mtime(file): + if os.path.isfile(file): + return os.path.getmtime(file) + return 0 + +def deps_name(dir, scad_name): + return dir + '/' + scad_name[:-5] + '.deps' + +def read_deps(dname): + with open(dname, "rt") as file: + lines = file.readlines() + deps = [] + for line in lines: + if line.startswith('\t'): + dep = line[1 : -1].rstrip(' \\') + if not dep in ['stl.scad', 'dxf.scad', 'svf.scad', 'png.scad']: + deps.append(dep) + return deps + +def check_deps(target_mtime, dname): + if not target_mtime: + return "target missing" + if not os.path.isfile(dname): + return "no deps" + deps = read_deps(dname) + for dep in deps: + if mtime(dep) > target_mtime: + return dep + ' changed' + return None diff --git a/scripts/dxfs.py b/scripts/dxfs.py new file mode 100644 index 0000000..cac98d2 --- /dev/null +++ b/scripts/dxfs.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function +import sys + +from exports import make_parts + +if __name__ == '__main__': + if len(sys.argv) > 1 and not '.' in sys.argv[1]: + target, parts = sys.argv[1], sys.argv[2:] + else: + target, parts = None, sys.argv[1:] + make_parts(target, 'dxf', parts) diff --git a/scripts/exports.py b/scripts/exports.py new file mode 100644 index 0000000..ad66134 --- /dev/null +++ b/scripts/exports.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function +import os +import openscad +import sys +import c14n_stl +from set_config import * +import time +import times +from deps import * + +def bom_to_parts(target_dir, part_type, assembly = None): + # + # Make a list of all the parts in the BOM + # + part_files = [] + bom = assembly + '.txt' if assembly else "bom.txt" + suffix = ".dxf" if part_type == 'svg' else '.' + part_type + with open(target_dir + "/../bom/" + bom, "rt") as f: + for line in f.readlines(): + words = line.split() + if words: + last_word = words[-1] + if last_word.endswith(suffix): + part_files.append(last_word[:-4] + '.' + part_type) + return part_files + +def make_parts(target, part_type, parts = None): + # + # Make the target directory + # + top_dir = set_config(target) + target_dir = top_dir + part_type + 's' + deps_dir = top_dir + "deps" + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + if not os.path.isdir(deps_dir): + os.makedirs(deps_dir) + times.read_times(target_dir) + # + # Decide which files to make + # + if parts: + targets = list(parts) #copy the list so we dont modify the list passed in + else: + targets = bom_to_parts(target_dir, part_type) + for file in os.listdir(target_dir): + if file.endswith('.' + part_type): + if not file in targets: + print("Removing %s" % file) + os.remove(target_dir + '/' + file) + # + # Find all the scad files + # + lib_dir = os.environ['OPENSCADPATH'] + '/NopSCADlib' + used = [] + module_suffix = '_dxf' if part_type == 'svg' else '_' + part_type + for dir in [source_dir, lib_dir]: + for filename in os.listdir(dir): + if filename[-5:] == ".scad": + # + # find any modules ending in _ + # + with open(dir + "/" + filename, "r") as f: + for line in f.readlines(): + words = line.split() + if(len(words) and words[0] == "module"): + module = words[1].split('(')[0] + if module.endswith(module_suffix): + base_name = module[:-4] + part = base_name + '.' + part_type + if part in targets: + # + # make a file to use the module + # + part_maker_name = part_type + ".scad" + with open(part_maker_name, "w") as f: + f.write("use <%s/%s>\n" % (dir, filename)) + f.write("%s();\n" % module); + # + # Run openscad on the created file + # + part_file = target_dir + "/" + part + dname = deps_name(deps_dir, filename) + changed = check_deps(mtime(part_file), dname) + changed = times.check_have_time(changed, part) + if changed: + print(changed) + t = time.time() + openscad.run("-D$bom=1", "-d", dname, "-o", part_file, part_maker_name) + times.add_time(part, t) + if part_type == 'stl': + c14n_stl.canonicalise(part_file) + targets.remove(part) + os.remove(part_maker_name) + # + # Add the files on the BOM to the used list for plates.py + # + for line in open("openscad.log"): + if line[:7] == 'ECHO: "' and line[-6:] == '.' + part_type + '"\n': + used.append(line[7:-2]) + # + # List the ones we didn't find + # + if targets: + for part in targets: + if part[-4:] != '.' + part_type: + print(part, "is not a", part_type, "file") + else: + print("Could not find a module called", part[:-4] + module_suffix, "to make", part) + sys.exit(1) + times.print_times() + return used diff --git a/scripts/gallery.py b/scripts/gallery.py new file mode 100644 index 0000000..4713847 --- /dev/null +++ b/scripts/gallery.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# +# 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 . +# + +# +# Find projects and add them to the gallery +# +from __future__ import print_function +import os +from colorama import Fore, init +from tests import do_cmd +import re +from shutil import copyfile + +project_dir = '../..' +target_dir = 'gallery' +output_name = target_dir + '/readme.md' + +def gallery(): + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + + projects = [i for i in os.listdir(project_dir) if os.path.isdir(project_dir + '/' + i + '/assemblies')] + with open(output_name, 'wt') as output_file: + for project in projects: + path = project_dir + '/' + project + print(project) + document = path + '/readme.md' + if os.path.isfile(document): + with open(document, 'rt') as readme: + for line in readme.readlines(): + match = re.match(r"^.*!(\[.*\]\(.*\)).*$", line) + if match: + image = match.group(0) + if image.startswith('![Main Assembly](assemblies/'): + file = image[17 : -1] + line = line.replace(image, '![](%s.png)' % project) + copyfile(path + '/' + file, '%s/%s.png' %(target_dir, project)) + else: + line = line.replace(image, '') + print(line[:-1], file = output_file) + if line == '---\n': + break; + else: + print(Fore.MAGENTA + "Can't find", document, Fore.WHITE); + with open(target_dir + "/readme.html", "wt") as html_file: + do_cmd(("python -m markdown -x tables " + output_name).split(), html_file) + +if __name__ == '__main__': + init() + gallery() diff --git a/scripts/make_all.py b/scripts/make_all.py new file mode 100644 index 0000000..bb6c4b1 --- /dev/null +++ b/scripts/make_all.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +# +# 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 . +# + +import sys + +from exports import make_parts +from bom import boms +from render import render +from views import views + +if __name__ == '__main__': + target = None if len(sys.argv) == 1 else sys.argv[1] + boms(target) + for part in ['stl', 'dxf']: + make_parts(target, part) + render(target, part) + views(target) diff --git a/scripts/openscad.py b/scripts/openscad.py new file mode 100644 index 0000000..b33e547 --- /dev/null +++ b/scripts/openscad.py @@ -0,0 +1,38 @@ +# +# 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 . +# + +# +# Run openscad +# +from __future__ import print_function + +import subprocess, sys + +def run(*args): + cmd = ["openscad"] + list(args) + for arg in cmd: + print(arg, end=" ") + print() + with open("openscad.log", "w") as log: + rc = subprocess.call(cmd, stdout = log, stderr = log) + for line in open("openscad.log", "rt"): + if 'ERROR:' in line or 'WARNING:' in line: + print(line[:-1]) + if rc: + sys.exit(rc) diff --git a/scripts/render.py b/scripts/render.py new file mode 100644 index 0000000..6b065d1 --- /dev/null +++ b/scripts/render.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function +from set_config import * +from exports import bom_to_parts +import os +import openscad +from tests import do_cmd +from deps import mtime + +def render(target, type): + # + # Make the target directory + # + target_dir = set_config(target) + type + 's' + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + # + # Find all the parts + # + parts = bom_to_parts(target_dir, type) + # + # Remove unused png files + # + for file in os.listdir(target_dir): + if file.endswith('.png'): + if not file[:-4] + '.' + type in parts: + print("Removing %s" % file) + os.remove(target_dir + '/' + file) + + for part in parts: + part_file = target_dir + '/' + part + png_name = target_dir + '/' + part[:-4] + '.png' + # + # make a file to import the stl + # + if mtime(part_file) > mtime(png_name): + png_maker_name = "png.scad" + with open(png_maker_name, "w") as f: + f.write('color("lime") import("%s");\n' % part_file) + cam = "--camera=0,0,0,70,0,315,500" if type == 'stl' else "--camera=0,0,0,0,0,0,500" + render = "--preview" if type == 'stl' else "--render" + openscad.run("--projection=p", "--imgsize=4096,4096", cam, render, "--autocenter", "--viewall", "-o", png_name, png_maker_name); + do_cmd(("magick "+ png_name + " -trim -resize 280x280 -background #ffffe5 -gravity Center -extent 280x280 -bordercolor #ffffe5 -border 10 " + png_name).split()) + os.remove(png_maker_name) + +if __name__ == '__main__': + target = sys.argv[1] if len(sys.argv) > 1 else None + render(target, 'stl') + render(target, 'dxf') diff --git a/scripts/set_config.py b/scripts/set_config.py new file mode 100644 index 0000000..69a6af9 --- /dev/null +++ b/scripts/set_config.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +# +# 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 . +# + +# +# Set target configuration for multi-target projects that have variable configurations. +# +from __future__ import print_function + +source_dir = 'scad' + +import sys +import os + +def valid_targets(): + return [i[7:-5] for i in os.listdir(source_dir) if i[0:7] == "config_" and i[-5:] == ".scad"] + +def valid_targets_string(): + result = '' + targets = valid_targets() + for t in targets: + if result: + if t == targets[-1]: + result += ' and ' + else: + result += ', ' + result += t + return result + + +def set_config(target): + targets = valid_targets() + if not target: + if not targets: + return "" + print("Must specify a configuration: " + valid_targets_string()) + sys.exit(1) + + if not targets: + print("Not a muli-configuration project (no config_.scad files found)") + sys.exit(1) + + if not target in targets: + print(target + " is not a configuration, avaliable configurations are: " + valid_targets_string()) + sys.exit(1) + + fname = source_dir + "/target.scad" + text = "include \n" % target; + line = "" + try: + with open(fname,"rt") as f: + line = f.read() + except: + pass + + if line != text: + with open(fname,"wt") as f: + f. write(text); + return target + "/" + +if __name__ == '__main__': + args = len(sys.argv) + if args == 2: + set_config(sys.argv[1]) + else: + print("usage: set_config config_name") + sys.exit(1) diff --git a/scripts/stls.py b/scripts/stls.py new file mode 100644 index 0000000..01d27d0 --- /dev/null +++ b/scripts/stls.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function +import sys + +from exports import make_parts + +if __name__ == '__main__': + if len(sys.argv) > 1 and not '.' in sys.argv[1]: + target, parts = sys.argv[1], sys.argv[2:] + else: + target, parts = None, sys.argv[1:] + make_parts(target, 'stl', parts) diff --git a/scripts/svgs.py b/scripts/svgs.py new file mode 100644 index 0000000..4cca176 --- /dev/null +++ b/scripts/svgs.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function +import sys + +from exports import make_parts + +if __name__ == '__main__': + if len(sys.argv) > 1 and not '.' in sys.argv[1]: + target, parts = sys.argv[1], sys.argv[2:] + else: + target, parts = None, sys.argv[1:] + make_parts(target, 'svg', parts) diff --git a/scripts/tests.py b/scripts/tests.py new file mode 100644 index 0000000..393a304 --- /dev/null +++ b/scripts/tests.py @@ -0,0 +1,230 @@ +#!/usr/bin/env python + +# +# 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 . +# + +from __future__ import print_function +import os +import sys +import openscad +import subprocess +import bom +import times +import time +import json +from deps import * +from blurb import * + +w = 4096 +h = w + +def do_cmd(cmd, output = sys.stdout): + for arg in cmd: + print(arg, end = " ") + print() + subprocess.call(cmd, stdout = output) + +def depluralise(name): + if name[-3:] == "ies" and name != "zipties": + return name[:-3] + 'y' + if name[-3:] == "hes": + return name[:-2] + if name[-1:] == 's': + return name[:-1] + return name + +def is_plural(name): + return name != depluralise(name) + +def tests(tests): + scad_dir = "tests" + deps_dir = scad_dir + "/deps" + png_dir = scad_dir + "/png" + bom_dir = scad_dir + "/bom" + for dir in [deps_dir, png_dir, bom_dir]: + if not os.path.isdir(dir): + os.makedirs(dir) + doc_name = "readme.md" + index = {} + bodies = {} + times.read_times() + # + # Make cover pic if does not exist as very slow. Delete it to force an update. + # + png_name = "libtest.png" + scad_name = "libtest.scad" + if not os.path.isfile(png_name): + openscad.run("--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,50,0,340,500", "--autocenter", "--viewall", "-o", png_name, scad_name); + do_cmd(["magick", png_name, "-trim", "-resize", "1280", "-bordercolor", "#ffffe5", "-border", "10", png_name]) + # + # List of individual part files + # + scads = [i for i in os.listdir(scad_dir) if i[-5:] == ".scad"] + + for scad in scads: + base_name = scad[:-5] + if not tests or base_name in tests: + print(base_name) + cap_name = base_name[0].capitalize() + base_name[1:] + scad_name = scad_dir + '/' + scad + png_name = png_dir + '/' + base_name + '.png' + bom_name = bom_dir + '/' + base_name + '.json' + + objects_name = None + vits_name = 'vitamins/' + base_name + '.scad' + if is_plural(base_name) and os.path.isfile(vits_name): + objects_name = vits_name + + locations = [ + ('vitamins/' + depluralise(base_name) + '.scad', 'Vitamins'), + (base_name + '.scad', 'Printed'), + ('utils/' + base_name + '.scad', 'Utilities'), + ('utils/core/' + base_name + '.scad', 'Core Utilities'), + ] + + for name, type in locations: + if os.path.isfile(name): + impl_name = name + break + else: + print("Can't find implementation!") + continue + + vsplit = "N" + vtype = locations[0][1] + types = [vtype + ' A-' + vsplit[0], vtype + ' ' + chr(ord(vsplit) + 1) + '-Z'] + [loc[1] for loc in locations[1 :]] + if type == vtype: + type = types[0] if cap_name[0] <= vsplit else types[1] + + if not type in bodies: + bodies[type] = [] + index[type] = [] + body = bodies[type] + + index[type] += [cap_name] + body += ['' % cap_name] + body += ["## " + cap_name] + + doc = None + if impl_name: + doc = scrape_code(impl_name) + blurb = doc["blurb"] + else: + blurb = scrape_blurb(scad_name) + + if not len(blurb): + print("Blurb not found!") + else: + body += [ blurb ] + + if objects_name: + body += ["[%s](%s) Object definitions.\n" % (objects_name, objects_name)] + + if impl_name: + body += ["[%s](%s) Implementation.\n" % (impl_name, impl_name)] + + body += ["[%s](%s) Code for this example.\n" % (scad_name.replace('\\','/'), scad_name)] + + if doc: + for thing in ["properties", "functions", "modules"]: + things = doc[thing] + if things: + body += ['### %s\n| | |\n|:--- |:--- |' % thing.title()] + for item in sorted(things): + body += ['| ```%s``` | %s |' % (item, things[item])] + body += [''] + + body += ["![%s](%s)\n" %(base_name, png_name)] + + dname = deps_name(deps_dir, scad) + oldest = min(mtime(png_name), mtime(bom_name)) + changed = check_deps(oldest, dname) + changed = times.check_have_time(changed, scad_name) + if changed: + print(changed) + t = time.time() + openscad.run("-D", "$bom=2", "--projection=p", "--imgsize=%d,%d" % (w, h), "--camera=0,0,0,70,0,315,500", "--autocenter", "--viewall", "-d", dname, "-o", png_name, scad_name); + times.add_time(scad_name, t) + do_cmd(["magick", png_name, "-trim", "-resize", "1000x600", "-bordercolor", "#ffffe5", "-border", "10", png_name]) + BOM = bom.parse_bom() + with open(bom_name, 'wt') as outfile: + json.dump(BOM.flat_data(), outfile, indent = 4) + + with open(bom_name, "rt") as bom_file: + BOM = json.load(bom_file) + for thing in ["vitamins", "printed", "routed", "assemblies"]: + things = BOM[thing] + if things: + body += ['### %s\n| | | |\n| ---:|:--- |:---|' % thing.title()] + for item in sorted(things, key = lambda s: s.split(":")[-1]): + name = item + desc = '' + if thing == "vitamins": + vit = item.split(':') + name = '```' + vit[0] + '```' if vit[0] else '' + while '[[' in name and ']]' in name: + i = name.find('[[') + j = name.find(']]') + 2 + name = name.replace(name[i : j], '[ ... ]') + desc = vit[1] + body += ['| %3d | %s | %s |' % (things[item], name, desc)] + body += [''] + + body += ['\nTop'] + body += ["\n---"] + + with open(doc_name, "wt") as doc_file: + print('# NopSCADlib', file = doc_file) + print('''\ +An ever expanding library of parts modelled in OpenSCAD useful for 3D printers and enclosures for electronics, etc. + +It contains lots of vitamins (the RepRap term for non-printed parts), some general purpose printed parts and +some utilities. There are also Python scripts to generate Bills of Materials (BOMs), + STL files for all the printed parts and DXF files for CNC routed parts in a project. + +\n +''', file = doc_file) + + print('## Table of Contents', file = doc_file) + print('', file = doc_file) + n = 0 + for type in types: + print('' % type, end = '', file = doc_file) + n = max(n, len(index[type])) + print('', file = doc_file) + for i in range(n): + print('', file = doc_file, end = '') + for type in types: + if i < len(index[type]): + name = index[type][i] + print('', file = doc_file, end = '') + else: + print('', file = doc_file, end = '') + print('', file = doc_file) + print('
%s
' + name + '
\n\n---', file = doc_file) + for type in types: + for line in bodies[type]: + print(line, file = doc_file) + with open("readme.html", "wt") as html_file: + do_cmd("python -m markdown -x tables readme.md".split(), html_file) + times.print_times() + do_cmd('codespell -L od readme.md'.split()) + +if __name__ == '__main__': + tests(sys.argv[1:]) diff --git a/scripts/times.py b/scripts/times.py new file mode 100644 index 0000000..f6e7acf --- /dev/null +++ b/scripts/times.py @@ -0,0 +1,71 @@ +# +# 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 . +# + +# show execution times and how they have changed. + +import json +import time +from colorama import Fore, init + +def read_times(dir = '.'): + global times, last_times, times_fname + times_fname = dir + '/times.txt' + init() + try: + with open(times_fname) as json_file: + times = json.load(json_file) + last_times = dict(times) + except: + times = {} + last_times = {} + +def write_times(): + with open(times_fname, 'w') as outfile: + json.dump(times, outfile, indent = 4) + +def got_time(name): + return name in last_times + +def check_have_time(changed, name): + if not changed and not got_time(name): + changed = "no previous time" + return changed + +def add_time(name, start): + times[name] = round(time.time() - start, 3) + +def print_times(): + write_times() + sorted_times = sorted(times.items(), key=lambda kv: kv[1]) + total = 0 + for entry in sorted_times: + colour = Fore.WHITE + key = entry[0] + new = entry[1] + delta = 0 + if key in last_times: + old = last_times[key] + delta = new - old + if delta > 0.3: + colour = Fore.RED + if delta < -0.3: + colour = Fore.GREEN + print(colour + "%5.1f %5.1f %s" % (new, delta, key)) + total += new + print(Fore.WHITE + "%5.1f" % total) diff --git a/scripts/views.py b/scripts/views.py new file mode 100644 index 0000000..8bdb095 --- /dev/null +++ b/scripts/views.py @@ -0,0 +1,345 @@ +#!/usr/bin/env python + +# +# 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 . +# + +# +#: Generate assembly views and intructions +# +from __future__ import print_function +from set_config import * +import openscad +from tests import do_cmd +import time +import times +from deps import * +import os +import json +import blurb +import bom +from colorama import Fore + +def is_assembly(s): + return s[-9:] == '_assembly' or s[-11:] == '_assemblies' + +def add_assembly(flat_bom, bom): + if not bom in flat_bom: + big = False + for ass in bom["assemblies"]: + add_assembly(flat_bom, ass) + if ass["routed"]: + big = True + bom["big"] = big or bom["routed"] + flat_bom.append(bom) + +def bom_to_assemblies(bom_dir): + global flat_bom + # + # Make a list of all the parts in the BOM + # + bom = {} + bom_file = bom_dir + "/bom.json" + with open(bom_file) as json_file: + bom = json.load(json_file) + flat_bom = [] + add_assembly(flat_bom, bom) + ass = flat_bom[-1] + if len(ass["assemblies"]) < 2 and not ass["vitamins"] and not ass["printed"] and not ass["routed"]: + flat_bom = flat_bom[:-1] + return [assembly["name"] for assembly in flat_bom] + +def eop(print_mode, project, doc_file, last = False, first = False): + if print_mode: + print('\n
', file = doc_file) + else: + if not first: + print('[Top](#%s)' % project.lower().replace(' ', '-'), file = doc_file) + if not last: + print("\n---", file = doc_file) + +def pad(s, before, after = 0): + return ' ' * before + str(s) + ' ' * after + +def views(target, do_assemblies = None): + done_assemblies = [] + # + # Make the target directory + # + top_dir = set_config(target) + target_dir = top_dir + 'assemblies' + deps_dir = top_dir + "deps" + bom_dir = top_dir + "bom" + if not os.path.isdir(target_dir): + os.makedirs(target_dir) + if not os.path.isdir(deps_dir): + os.makedirs(deps_dir) + times.read_times(target_dir) + # + # Find all the assemblies + # + assemblies = bom_to_assemblies(bom_dir) + for file in os.listdir(target_dir): + if file.endswith('.png'): + assembly = file[:-4].replace('_assembled', '_assembly') + if assembly.endswith('_tn'): + assembly = assembly[:-3] + if not assembly in assemblies: + print("Removing %s" % file) + os.remove(target_dir + '/' + file) + # + # Find all the scad files + # + main_blurb = None + lib_dir = os.environ['OPENSCADPATH'] + '/NopSCADlib' + for dir in [source_dir, lib_dir]: + for filename in os.listdir(dir): + if filename.endswith('.scad'): + # + # find any modules with names ending in _assembly + # + with open(dir + "/" + filename, "r") as f: + lines = f.readlines() + line_no = 0 + for line in lines: + words = line.split() + if len(words) and words[0] == "module": + module = words[1].split('(')[0] + if is_assembly(module): + if module in assemblies: + # + # Scrape the assembly instructions + # + for ass in flat_bom: + if ass["name"] == module: + if not "blurb" in ass: + ass["blurb"] = blurb.scrape_module_blurb(lines[:line_no]) + break + if not do_assemblies or module in do_assemblies: + # + # make a file to use the module + # + png_maker_name = 'png.scad' + with open(png_maker_name, "w") as f: + f.write("use <%s/%s>\n" % (dir, filename)) + f.write("%s();\n" % module); + # + # Run openscad on the created file + # + dname = deps_name(deps_dir, filename) + for explode in [0, 1]: + png_name = target_dir + '/' + module + '.png' + if not explode: + png_name = png_name.replace('_assembly', '_assembled') + changed = check_deps(mtime(png_name), dname) + changed = times.check_have_time(changed, png_name) + if changed: + print(changed) + t = time.time() + openscad.run("-D$pose=1", "-D$explode=%d" % explode, "--projection=p", "--imgsize=4096,4096", "--autocenter", "--viewall", "-d", dname, "-o", png_name, png_maker_name); + times.add_time(png_name, t) + do_cmd(["magick", png_name, "-trim", "-resize", "1004x1004", "-bordercolor", "#ffffe5", "-border", "10", png_name]) + tn_name = png_name.replace('.png', '_tn.png') + if mtime(png_name) > mtime(tn_name): + do_cmd(("magick "+ png_name + " -trim -resize 280x280 -background #ffffe5 -gravity Center -extent 280x280 -bordercolor #ffffe5 -border 10 " + tn_name).split()) + os.remove(png_maker_name) + done_assemblies.append(module) + else: + if module == 'main_assembly': + main_blurb = blurb.scrape_module_blurb(lines[:line_no]) + line_no += 1 + times.print_times() + # + # Build the document + # + for print_mode in [True, False]: + doc_name = top_dir + "readme.md" + with open(doc_name, "wt") as doc_file: + # + # Title, description and picture + # + project = ' '.join(word[0].upper() + word[1:] for word in os.path.basename(os.getcwd()).split('_')) + print('# %s' % project, file = doc_file) + main_file = bom.find_scad_file('main_assembly') + if not main_file: + raise Exception("can't find source for main_assembly") + text = blurb.scrape_blurb(source_dir + '/' + main_file) + if len(text): + print(text, file = doc_file, end = '') + else: + if print_mode: + print(Fore.MAGENTA + "Missing project description" + Fore.WHITE) + print('![Main Assembly](assemblies/%s.png)\n' % flat_bom[-1]["name"].replace('_assembly', '_assembled'), file = doc_file) + eop(print_mode, project, doc_file, first = True) + # + # Build TOC + # + print('## Table of Contents', file = doc_file) + print('[TOC]\n', file = doc_file) + eop(print_mode, project, doc_file) + # + # Global BOM + # + print('## Parts list', file = doc_file) + vitamins = {} + printed = {} + routed = {} + for ass in flat_bom: + for v in ass["vitamins"]: + if v in vitamins: + vitamins[v] += ass["vitamins"][v] + else: + vitamins[v] = ass["vitamins"][v] + for p in ass["printed"]: + if p in printed: + printed[p] += ass["printed"][p] + else: + printed[p] = ass["printed"][p] + for ass in flat_bom: + name = ass["name"][:-9].replace('_', ' ').title().replace(' ',' ') + print('| %s ' % name, file = doc_file, end = '') + print('| TOTALS | |', file = doc_file) + print(('|--:' * len(flat_bom) + '|--:|:--|'), file = doc_file) + for v in sorted(vitamins, key = lambda s: s.split(":")[-1]): + for ass in flat_bom: + count = ass["vitamins"][v] if v in ass["vitamins"] else '.' + print('| %s ' % pad(count, 2, 1), file = doc_file, end = '') + print('| %s | %s |' % (pad(vitamins[v], 2, 1), pad(v.split(":")[1], 2)), file = doc_file) + print(('| ' * len(flat_bom) + '| | **3D Printed parts** |'), file = doc_file) + for p in sorted(printed): + for ass in flat_bom: + count = ass["printed"][p] if p in ass["printed"] else '.' + print('| %s ' % pad(count, 2, 1), file = doc_file, end = '') + print('| %s | %s |' % (pad(printed[p], 2, 1), pad(p, 3)), file = doc_file) + eop(print_mode, project, doc_file) + # + # Assembly instructions + # + for ass in flat_bom: + name = ass["name"] + cap_name = name.replace('_', ' ').title() + if ass["count"] > 1: + print("## %d x %s" % (ass["count"], cap_name), file = doc_file) + else: + print("## %s" % cap_name, file = doc_file) + vitamins = ass["vitamins"] + if vitamins: + print("### Vitamins", file = doc_file) + print("|Qty|Description|", file = doc_file) + print("|--:|:----------|", file = doc_file) + for v in vitamins: + print("|%d|%s|" % (vitamins[v], v.split(":")[1]), file = doc_file) + print("\n", file = doc_file) + + printed = ass["printed"] + if printed: + print('### 3D Printed parts', file = doc_file) + i = 0 + for p in printed: + print('%s %d x %s |' % ('\n|' if not (i % 3) else '', printed[p], p), file = doc_file, end = '') + if (i % 3) == 2 or i == len(printed) - 1: + n = (i % 3) + 1 + print('\n|%s' % ('--|' * n), file = doc_file) + for j in range(n): + part = list(printed.keys())[i - n + j + 1] + print('| ![%s](stls/%s) %s' % (part, part.replace('.stl','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file) + print('\n', file = doc_file) + i += 1 + print('\n', file = doc_file) + + routed = ass["routed"] + if routed: + print("### CNC Routed parts", file = doc_file) + i = 0 + for r in routed: + print('%s %d x %s |' % ('\n|' if not (i % 3) else '', routed[r], r), file = doc_file, end = '') + if (i % 3) == 2 or i == len(routed) - 1: + n = (i % 3) + 1 + print('\n|%s' % ('--|' * n), file = doc_file) + for j in range(n): + part = list(routed.keys())[i - n + j + 1] + print('| ![%s](dxfs/%s) %s' % (part, part.replace('.dxf','.png'), '|\n' if j == j - 1 else ''), end = '', file = doc_file) + print('\n', file = doc_file) + i += 1 + print('\n', file = doc_file) + + sub_assemblies = ass["assemblies"] + if sub_assemblies: + print("### Sub-assemblies", file = doc_file) + i = 0 + for a in sub_assemblies: + print('%s %d x %s |' % ('\n|' if not (i % 3) else '', a["count"], a["name"]), file = doc_file, end = '') + if (i % 3) == 2 or i == len(sub_assemblies) - 1: + n = (i % 3) + 1 + print('\n|%s' % ('--|' * n), file = doc_file) + for j in range(n): + a = sub_assemblies[i - n + j + 1]["name"].replace('_assembly', '_assembled') + print('| ![%s](assemblies/%s) %s' % (a, a + '_tn.png', '|\n' if j == j - 1 else ''), end = '', file = doc_file) + print('\n', file = doc_file) + i += 1 + print('\n', file = doc_file) + + small = not ass["big"] + suffix = '_tn.png' if small else '.png' + print('### Assembly instructions', file = doc_file) + print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file) + + if "blurb" in ass and ass["blurb"]: + print(ass["blurb"], file = doc_file) + else: + if print_mode: + print(Fore.MAGENTA + "Missing instructions for %s" % name, Fore.WHITE) + + name = name.replace('_assembly', '_assembled') + print('![%s](assemblies/%s)\n' % (name, name + suffix), file = doc_file) + eop(print_mode, project, doc_file, last = ass == flat_bom[-1] and not main_blurb) + # + # If main module is suppressed print any blurb here + # + if main_blurb: + print(main_blurb, file = doc_file) + eop(print_mode, project, doc_file, last = True) + # + # Convert to HTML + # + html_name = "printme.html" if print_mode else "readme.html" + with open(top_dir + html_name, "wt") as html_file: + do_cmd(("python -m markdown -x tables -x toc -x sane_lists " + doc_name).split(), html_file) + # + # Spell check + # + do_cmd('codespell -L od readme.md'.split()) + # + # List the ones we didn't find + # + missing = set() + for assembly in assemblies + (do_assemblies if do_assemblies else []): + if assembly not in done_assemblies: + missing.add(assembly) + if missing: + for assembly in missing: + print(Fore.MAGENTA + "Could not find a module called", assembly, Fore.WHITE) + sys.exit(1) + +if __name__ == '__main__': + if len(sys.argv) > 1 and sys.argv[1][-9:] != "_assembly": + target, assemblies = sys.argv[1], sys.argv[2:] + else: + target, assemblies = None, sys.argv[1:] + + views(target, assemblies) diff --git a/socket_box.scad b/socket_box.scad new file mode 100644 index 0000000..aa02bc9 --- /dev/null +++ b/socket_box.scad @@ -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 . +// + +// +//! UK 13A socket and printed backbox with earth terminal for the panel it is mounted on. +// +include +include +include +include +include + +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°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); +} diff --git a/strap_handle.scad b/strap_handle.scad new file mode 100644 index 0000000..de20184 --- /dev/null +++ b/strap_handle.scad @@ -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 . +// + +// +//! 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 +include +include + +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°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); + } +} diff --git a/tests/annotation.scad b/tests/annotation.scad new file mode 100644 index 0000000..37d3c1b --- /dev/null +++ b/tests/annotation.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/annotation.scad> + +module annotations() { + arrow(); + + translate_z(21) + label("Text", halign = "center", valign = "bottom"); +} + +if($preview) + annotations(); diff --git a/tests/ball_bearings.scad b/tests/ball_bearings.scad new file mode 100644 index 0000000..4b5f356 --- /dev/null +++ b/tests/ball_bearings.scad @@ -0,0 +1,30 @@ +// +// 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 . +// + +use <../utils/layout.scad> + +include <../vitamins/ball_bearings.scad> + +module ball_bearings() + layout([for(b = ball_bearings) bb_diameter(b)]) + ball_bearing(ball_bearings[$i]) + bearing_ball(3); + +if($preview) + ball_bearings(); diff --git a/tests/batteries.scad b/tests/batteries.scad new file mode 100644 index 0000000..a7d2b5f --- /dev/null +++ b/tests/batteries.scad @@ -0,0 +1,41 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/springs.scad> +include <../vitamins/batteries.scad> + +module batteries() + layout([for(b = batteries) battery_diameter(b)], 5) let(battery=batteries[$i]) { + battery = batteries[$i]; + rotate(-135) // To show Lumintop USB socket and LEDs + battery(battery); + + contact = battery_contact(battery); + translate_z(battery_length(battery) / 2 + contact_pos(contact).x) + rotate([0, 180, 0]) + battery_contact(contact); + + translate_z(-battery_length(battery) / 2 - contact_neg(contact).x) + battery_contact(contact, false); + } + +if($preview) + batteries(); diff --git a/tests/belts.scad b/tests/belts.scad new file mode 100644 index 0000000..d7d8d40 --- /dev/null +++ b/tests/belts.scad @@ -0,0 +1,74 @@ +// +// 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 . +// +include <../core.scad> + +include <../vitamins/belts.scad> +include <../vitamins/screws.scad> +include <../vitamins/inserts.scad> +include <../vitamins/pulleys.scad> +use <../utils/layout.scad> + +module belt_test() { + p1 = [75, -50]; + p2 = [-75, -50]; + p3 = [-75, 100]; + p4 = [75, 100]; + + p5 = [75 - pulley_pr(GT2x20ob_pulley) - pulley_pr(GT2x16_plain_idler), -pulley_pr(GT2x16_plain_idler)]; + p6 = [-75 + pulley_pr(GT2x20ob_pulley) + pulley_pr(GT2x16_plain_idler), -pulley_pr(GT2x16_plain_idler)]; + + translate(p1) pulley_assembly(GT2x20ob_pulley); + translate(p2) pulley_assembly(GT2x20ob_pulley); + translate(p3) pulley_assembly(GT2x20_toothed_idler); + translate(p4) pulley_assembly(GT2x20_toothed_idler); + + translate(p5) { + pulley = GT2x16_plain_idler; + screw = find_screw(hs_cs_cap, pulley_bore(pulley)); + insert = screw_insert(screw); + + pulley_assembly(pulley); + translate_z(pulley_height(pulley) + pulley_offset(pulley) + screw_head_depth(screw, pulley_bore(pulley))) + screw(screw, 20); + + translate_z(pulley_offset(pulley) - insert_length(insert)) + vflip() + insert(insert); + + } + translate(p6) pulley_assembly(GT2x16_plain_idler); + + path = [ [p1.x, p1.y, pulley_pr(GT2x20ob_pulley)], + [p5.x, p5.y, -pulley_pr(GT2x16_plain_idler)], + [p6.x, p6.y, -pulley_pr(GT2x16_plain_idler)], + [p2.x, p2.y, pulley_pr(GT2x20ob_pulley)], + [p3.x, p3.y, pulley_pr(GT2x20ob_pulley)], + [p4.x, p4.y, pulley_pr(GT2x20ob_pulley)] + ]; + belt = GT2x6; + belt(belt, path, 80, [0, belt_pitch_height(belt) - belt_thickness(belt) / 2]); + + translate([-25, 0]) + layout([for(b = belts) belt_width(b)], 10) + rotate([0, 90, 0]) + belt(belts[$i], [[0, 0, 20], [0, 1, 20]]); +} + +if($preview) + belt_test(); diff --git a/tests/bezier.scad b/tests/bezier.scad new file mode 100644 index 0000000..7a7cd69 --- /dev/null +++ b/tests/bezier.scad @@ -0,0 +1,83 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/bezier.scad> +use <../utils/sweep.scad> +use <../utils/annotation.scad> + +function find_min_z(path, i = 1, best_i = 0) = + i >= len(path) ? best_i + : find_min_z(path, i + 1, path[i].z < path[best_i].z ? i : best_i); + +module beziers() { + // + // Make Bezier control points to give specified length + // + control_points = adjust_bezier_length([[0, 0, 100], [0, 0, 0], [200, 0, 20], [100, -100, 50]], 250); + // + // Draw control points + // + color("green") + for(p = control_points) + translate(p) + sphere(1); + // + // Lines joining the control points + // + color("red") + sweep(control_points, circle_points(0.5, $fn = 64)); + // + // Bezier curve path from control points + // + curve = bezier_path(control_points); + // + // Draw the curve + // + sweep(curve, circle_points(2, $fn = 64)); + // + // Length computed from control points + // + length = bezier_length(control_points); + // + // Length computed from curve + // + length2 = path_length(curve); + assert(str(length) == str(length2), str(length, " ", length2)); + // + // Minimum Z + // + min_z = bezier_min_z(control_points); + i = find_min_z(curve); + assert(str(min_z) == str(curve[i].z)); + + color("blue") { + translate(curve[i] + [0, 0, 2]) + arrow(); + + translate(curve[i] - [0, 0, 2]) + vflip() + arrow(); + } + + translate(control_points[1] - [0, 0, 2]) + label(str("bezier_length = ", length, ", bezier_min_z = ", bezier_min_z(curve)), valign = "top"); +} + +if($preview) + beziers(); diff --git a/tests/blowers.scad b/tests/blowers.scad new file mode 100644 index 0000000..7e28072 --- /dev/null +++ b/tests/blowers.scad @@ -0,0 +1,41 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/blowers.scad> + +module blowers() + layout([for(b = blowers) blower_width(b)], 10, true) let(b = blowers[$i]){ + screw = blower_screw(b); + washer = screw_washer(screw); + h = blower_lug(b); + + blower(b); + + blower_hole_positions(b) + translate_z(h) + screw_and_washer(screw, screw_longer_than(h + washer_thickness(washer) + 5)); + + + } + +if($preview) + blowers(); diff --git a/tests/bom.scad b/tests/bom.scad new file mode 100644 index 0000000..f6da423 --- /dev/null +++ b/tests/bom.scad @@ -0,0 +1,108 @@ +// +// 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 . +// + +// +//! BOM and assembly demonstration +// +include <../core.scad> +include <../vitamins/screws.scad> +include <../vitamins/inserts.scad> +include <../vitamins/sheets.scad> +$explode = 1; // Normally set on the command line when generating assembly views with views.py + +screw = M3_cap_screw; +sheet = PMMA3; +height = 10; + +insert = screw_insert(screw); +washer = screw_washer(screw); + +module widget(thickness) { + vitamin(str("widget(", thickness, "): Rivit like thing for ", thickness, "mm sheets")); + t = 1; + color("silver") { + cylinder(d = 3, h = thickness + 2 * eps, center = true); + + for(end = [-1, 1]) + translate_z(end * (thickness / 2 + t / 2 + eps)) + cylinder(d = 4, h = t, center = true); + } +} + +module widgit_stl() { + stl("widget"); + + union() { + rounded_rectangle([30, 30, 3], 2); + + render() insert_boss(insert, height, 2.2); + } +} + +module widgit_dxf() { + dxf("widget"); + + difference() { + sheet_2D(sheet, 20, 20, 1); + + drill(screw_clearance_radius(screw), 0); + } +} + +//! * Push the insert into the base with a soldering iron heated to 200°C +module widgit_base_assembly() +assembly("widgit_base") { + color(pp1_colour) + widgit_stl(); + + translate_z(height) + insert(insert); +} + +//! * Magically insert the widget into the acrylic sheet +module widget_top_assembly() +assembly("widget_top") { + translate([-5, 5]) + widget(sheet_thickness(sheet)); + + render_2D_sheet(sheet) // Must be last because it is transparent + widgit_dxf(); +} + +//! * Screw the two assemblies together +module widgit_assembly() +assembly("wigdit") { + + widgit_base_assembly(); // Note this is not exloded because it is sub-assembly + + translate_z(height) { + translate_z(sheet_thickness(sheet)) + screw_and_washer(screw, screw_longer_than(sheet_thickness(sheet) + 2 * washer_thickness(washer) + 3), true); + + explode(5) + translate_z(sheet_thickness(sheet) / 2 + eps) + widget_top_assembly(); + } +} + +module boms() { + widgit_assembly(); +} + +boms(); diff --git a/tests/box.scad b/tests/box.scad new file mode 100644 index 0000000..531b06e --- /dev/null +++ b/tests/box.scad @@ -0,0 +1,54 @@ +// +// 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 . +// +include <../core.scad> + +include <../vitamins/screws.scad> +include <../vitamins/sheets.scad> +include <../vitamins/inserts.scad> + +use <../box.scad> + +box = [M3_dome_screw, 3, DiBond, PMMA3, DiBond6, true, 150, 100, 70]; + +include <../box_assembly.scad> + +module box_assembly() _box_assembly(box); + +module box_test() { + translate_z(box_height(box) / 2 + box_bezel_height(box, true)) + box_assembly(); + + rows = 3; + cols = 3; + gap = 30; + + x_pitch = (box_width(box) + 2 * box_outset(box)) / cols + gap; + y_pitch = (box_depth(box) + 2 * box_outset(box)) / rows + gap; + for(x = [0 : cols - 1], y = [0 : rows - 1]) + translate([(x - cols / 2) * x_pitch + gap / 2, (y - rows / 2) * y_pitch + gap / 2]) + color((x + y) % 2 ? pp1_colour : pp2_colour) box_bezel_section(box, true, rows, cols, x, y); + + translate([-cols / 2 * x_pitch - 20, 0]) + for(i = [0 : 2]) + translate([0, (i - 1) * 20, 0]) + color(i % 2 ? pp1_colour : pp2_colour) box_corner_profile_section(box, i, 3); +} + +if($preview) + box_test(); diff --git a/tests/bulldogs.scad b/tests/bulldogs.scad new file mode 100644 index 0000000..13b2d18 --- /dev/null +++ b/tests/bulldogs.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/bulldogs.scad> + +module bulldogs() + layout([for(b = bulldogs) bulldog_depth(b)], 5, true) + bulldog(bulldogs[$i]); + +if($preview) + bulldogs(); diff --git a/tests/butt_box.scad b/tests/butt_box.scad new file mode 100644 index 0000000..1a8d419 --- /dev/null +++ b/tests/butt_box.scad @@ -0,0 +1,66 @@ +// +// 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 . +// +include <../core.scad> + +include <../vitamins/screws.scad> +include <../vitamins/sheets.scad> +include <../vitamins/inserts.scad> + +include <../butt_box.scad> + +$explode = 0; + +box = [M3_dome_screw, DiBond, DiBond6, PMMA3, 250, 400, 300, 120]; + +module bbox_assembly() _bbox_assembly(box); + +module bbox_test() { + translate_z(bbox_height(box) / 2) + bbox_assembly(); +} + +if($preview) + bbox_test(); +else { + gap = 2; + bb = sheet_thickness(bbox_base_sheet(box)); + bt = sheet_thickness(bbox_top_sheet(box)); + h = bbox_height(box) + bb; + h2 = h + bt; + + bbox_base_blank(box); + + translate([bbox_width(box) / 2 + gap + h / 2 - bb / 2, 0]) + rotate(90) + bbox_right_blank(box); + + translate([-bbox_width(box) / 2 - gap - h / 2 + bb / 2, 0]) + rotate(-90) + bbox_left_blank(box); + + translate([0, bbox_depth(box) / 2 + gap + h / 2 - bb / 2]) + rotate(180) + bbox_back_blank(box); + + translate([0, -bbox_depth(box) / 2 - gap - h2 / 2 - (bt - bb) / 2]) + bbox_front_blank(box); + + translate([0, -bbox_depth(box) / 2 - gap - h2 - gap - bbox_depth(box) / 2 - sheet_thickness(bbox_sheets(box))]) + bbox_top_blank(box); +} diff --git a/tests/buttons.scad b/tests/buttons.scad new file mode 100644 index 0000000..8445e43 --- /dev/null +++ b/tests/buttons.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/buttons.scad> + +module buttons() + layout([for(b = buttons) square_button_width(b)], 5) + square_button(buttons[$i]); + +if($preview) + buttons(); diff --git a/tests/cable_grommets.scad b/tests/cable_grommets.scad new file mode 100644 index 0000000..e0faa28 --- /dev/null +++ b/tests/cable_grommets.scad @@ -0,0 +1,36 @@ +// +// 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 . +// +include <../core.scad> + +use <../cable_grommets.scad> + +module cable_grommets() { + rotate(90) + color(pp1_colour) ribbon_grommet(20, 3); + + translate([20, 0]) + round_grommet_assembly(6, 3); + + translate([40, 0]) + rotate(90) + color(pp1_colour) mouse_grommet(5, 3); +} + +if($preview) + cable_grommets(); diff --git a/tests/cable_strips.scad b/tests/cable_strips.scad new file mode 100644 index 0000000..18b214c --- /dev/null +++ b/tests/cable_strips.scad @@ -0,0 +1,38 @@ +// +// 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 . +// +include <../core.scad> + +use <../vitamins/cable_strip.scad> + +module cable_strips() { + depth = 50; + rotate(-90) + for(pos = [-100, 0, 100]) { + bezier_cable_strip(ways = 20, depth = depth, length = 150, travel = 100, pos = pos, below = 100, extra = 10); + + translate([0, depth * 2]) + rotate([0, -90, 0]) + cable_strip(ways =20, depth = depth / 2, travel = 100, x = pos, extra = 30); + + + } +} + +if($preview) + cable_strips(); diff --git a/tests/carriers.scad b/tests/carriers.scad new file mode 100644 index 0000000..db4e1ce --- /dev/null +++ b/tests/carriers.scad @@ -0,0 +1,25 @@ +// +// 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 . +// +include <../core.scad> +use <../carriers.scad> + +module carriers() + color(pp1_colour) ESP12F_carrier_stl(); + +carriers(); diff --git a/tests/clip.scad b/tests/clip.scad new file mode 100644 index 0000000..28f62a1 --- /dev/null +++ b/tests/clip.scad @@ -0,0 +1,26 @@ +// +// 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 . +// + +include <../core.scad> + +module clips() { + clip(xmin = 0, ymin = 0, zmin = 0, zmax = 40) sphere(50); +} + +clips(); diff --git a/tests/components.scad b/tests/components.scad new file mode 100644 index 0000000..054cf0d --- /dev/null +++ b/tests/components.scad @@ -0,0 +1,57 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/components.scad> + +module resistors() + layout([for(r = resistors) resistor_diameter(r)], 10) + resistor(resistors[$i]); + +module al_clad_resistors() + layout([for(a = al_clad_resistors) al_clad_width(a)]) + rotate(90) + al_clad_resistor_assembly(al_clad_resistors[$i], 4.7) + screw(al_clad_hole(al_clad_resistors[$i]) > 3 ? M3_pan_screw : M2p5_pan_screw, 16); + + +module thermal_cutouts() + layout([for(t = thermal_cutouts) tc_length(t)]) + thermal_cutout(thermal_cutouts[$i]); + +module components() { + resistors(); + + translate([0, 50]) + TO220("Generic TO220 package"); + + translate([30, 50]) + panel_USBA(); + + translate([0,80]) + thermal_cutouts(); + + translate([0, 130]) + al_clad_resistors(); +} + +if($preview) + components(); diff --git a/tests/corner_block.scad b/tests/corner_block.scad new file mode 100644 index 0000000..6972430 --- /dev/null +++ b/tests/corner_block.scad @@ -0,0 +1,37 @@ +// +// 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 . +// +include <../core.scad> +use <../corner_block.scad> + +include <../vitamins/screws.scad> + +screws = [M2_cap_screw, M2p5_pan_screw, M3_dome_screw, M4_dome_screw]; + +module do_corner_block(screw) + if($preview) + fastened_corner_block_assembly(3, screw = screw); + else + corner_block(screw); + +module corner_blocks() + for(i = [0 : len(screws) - 1]) + translate([i * 30, 0]) + do_corner_block(screws[i]); + +corner_blocks(); diff --git a/tests/d_connectors.scad b/tests/d_connectors.scad new file mode 100644 index 0000000..3398208 --- /dev/null +++ b/tests/d_connectors.scad @@ -0,0 +1,38 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/d_connectors.scad> + +module d_connectors() + for(socket = [false, true]) + translate([socket ? len(d_connectors) * (d_flange_width(d_connectors[0]) + 10) : 0, 0]) + layout([for(d = d_connectors) d_flange_width(d)], 10) let(d = d_connectors[$i]) + rotate(90) { + d_plug(d, socket, pcb = $i == 2, idc = $i == 1); + + if(socket) + translate_z(d_flange_thickness(d)) + d_connector_holes(d) + d_pillar(); + } + +if($preview) + d_connectors(); diff --git a/tests/displays.scad b/tests/displays.scad new file mode 100644 index 0000000..7f4e129 --- /dev/null +++ b/tests/displays.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +use <../utils/layout.scad> + +include <../vitamins/displays.scad> +use <../vitamins/pcb.scad> + +module displays() + layout([for(d = displays) pcb_length(display_pcb(d))], 10) + display(displays[$i]); + +if($preview) + displays(); diff --git a/tests/dogbones.scad b/tests/dogbones.scad new file mode 100644 index 0000000..44b64ca --- /dev/null +++ b/tests/dogbones.scad @@ -0,0 +1,34 @@ +// +// 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 . +// +include <../global_defs.scad> +use <../utils/dogbones.scad> + +module dogbones() { + #linear_extrude(height = eps) + dogbone_square([10, 20]); + + #translate([15, 0]) + dogbone_rectangle([10, 20, 5], center = false); + + sq = 3; + translate([-5 + sq / 2 + eps, -10 + sq / 2 + eps]) + %cube([sq, sq, 1], center = true); +} + +dogbones(); diff --git a/tests/door_hinge.scad b/tests/door_hinge.scad new file mode 100644 index 0000000..ace09fb --- /dev/null +++ b/tests/door_hinge.scad @@ -0,0 +1,57 @@ +// +// 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 . +// +include <../core.scad> +use <../door_hinge.scad> + +include <../vitamins/sheets.scad> +use <../vitamins/screw.scad> + +door_w = 50; +door_h = 50; +sheet = PMMA6; + +module door_hinges() { + translate([door_hinge_stat_length() / 2 - door_hinge_pin_x(), 0]) + if($preview) { + for(side = [-1, 1]) + translate_z(side * door_h / 2) { + door_hinge_assembly(side > 0, sheet_thickness(sheet)); + + door_hinge_static_assembly(side > 0, 3); + } + + translate([door_w / 2 + eps, door_hinge_pin_y() - eps]) + rotate([90, 0, 0]) + render_2D_sheet(sheet) + difference() { + sheet_2D(sheet, door_w, door_h, 3); + + for(z =[-1, 1]) + translate([-door_w / 2, z * door_h / 2]) + door_hinge_hole_positions(z) + drill(screw_pilot_hole(door_hinge_screw()), 0); + } + translate([door_w, 0]) + children(); + } + else + door_hinge_parts_stl(); +} + +door_hinges(); diff --git a/tests/door_latch.scad b/tests/door_latch.scad new file mode 100644 index 0000000..9ee24dc --- /dev/null +++ b/tests/door_latch.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../door_latch.scad> + +module door_latches() + translate([door_latch_offset(), 0]) + if($preview) + door_latch_assembly(3); + else + door_latch_stl(); + +door_latches(); diff --git a/tests/fan_guard.scad b/tests/fan_guard.scad new file mode 100644 index 0000000..4ac5c8b --- /dev/null +++ b/tests/fan_guard.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../fan_guard.scad> +include <../vitamins/fans.scad> + +module fan_guards() + layout([for(f = fans) fan_width(f)], 10) + color(pp1_colour) fan_guard(fans[$i], spokes = fan_width(fans[$i]) > 40 ? 8 : 4); + +fan_guards(); diff --git a/tests/fans.scad b/tests/fans.scad new file mode 100644 index 0000000..539beb1 --- /dev/null +++ b/tests/fans.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../fan_guard.scad> + +include <../vitamins/fans.scad> + +module fans() + layout([for(f = fans) fan_width(f)], 10) + fan_assembly(fans[$i], 3 + fan_guard_thickness(), true); + +if($preview) + fans(); diff --git a/tests/fillet.scad b/tests/fillet.scad new file mode 100644 index 0000000..4a5d0bb --- /dev/null +++ b/tests/fillet.scad @@ -0,0 +1,26 @@ +// +// 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 . +// +include <../global_defs.scad> +use <../utils/fillet.scad> + +module fillets() { + fillet(3, 25); +} + +fillets(); diff --git a/tests/fixing_block.scad b/tests/fixing_block.scad new file mode 100644 index 0000000..145bae6 --- /dev/null +++ b/tests/fixing_block.scad @@ -0,0 +1,37 @@ +// +// 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 . +// +include <../core.scad> +use <../fixing_block.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> + +screws = [M2_cap_screw, M2p5_pan_screw, M3_dome_screw, M4_dome_screw]; + +module fixing_block_test(screw) + if($preview) + fastened_fixing_block_assembly(3, screw = screw); + else + fixing_block(screw); + +module fixing_blocks() + layout([for(s = screws) fixing_block_width(s)], 5) + fixing_block_test(screws[$i]); + +fixing_blocks(); diff --git a/tests/foot.scad b/tests/foot.scad new file mode 100644 index 0000000..39e8bb8 --- /dev/null +++ b/tests/foot.scad @@ -0,0 +1,37 @@ +// +// 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 . +// +include <../core.scad> +use <../foot.scad> + +module feet() + if($preview) { + translate([50, 0]) + foot_assembly(3); + + translate([foot_diameter(insert_foot()) / 2, 0]) + fastened_insert_foot_assembly(3); + } + else { + translate([50, 0]) + foot(); + + insert_foot(); + } + +feet(); diff --git a/tests/fuseholder.scad b/tests/fuseholder.scad new file mode 100644 index 0000000..313b852 --- /dev/null +++ b/tests/fuseholder.scad @@ -0,0 +1,27 @@ +// +// 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 . +// +include <../core.scad> + +use <../vitamins/fuseholder.scad> + +module fuseholders() + fuseholder(6); + +if($preview) + fuseholders(); diff --git a/tests/global.scad b/tests/global.scad new file mode 100644 index 0000000..e987814 --- /dev/null +++ b/tests/global.scad @@ -0,0 +1,31 @@ +// +// 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 . +// + +include <../core.scad> + +module globals() { + linear_extrude(height = eps) { + semi_circle(r = 10); + + translate([30, 0]) + ellipse(15, 7); + } +} + +rotate([70, 0, 315]) globals(); diff --git a/tests/handle.scad b/tests/handle.scad new file mode 100644 index 0000000..42edac4 --- /dev/null +++ b/tests/handle.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../handle.scad> + +module handle() + translate([handle_length() / 2, 0]) + if($preview) + handle_fastened_assembly(3); + else + handle_stl(); + +handle(); diff --git a/tests/hanging_hole.scad b/tests/hanging_hole.scad new file mode 100644 index 0000000..0490908 --- /dev/null +++ b/tests/hanging_hole.scad @@ -0,0 +1,28 @@ +// +// 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 . +// +include <../global_defs.scad> +use <../utils/hanging_hole.scad> + +module hanging_holes() { + rotate(45) + #hanging_hole(z = 10, ir = 3, h = 30) + circle(r = 10); +} + +hanging_holes(); diff --git a/tests/hot_ends.scad b/tests/hot_ends.scad new file mode 100644 index 0000000..d1d7b33 --- /dev/null +++ b/tests/hot_ends.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/hot_ends.scad> + +module hot_ends() + layout([for(h = hot_ends) 40]) + translate([-20, 0]) + rotate(90) + hot_end(hot_ends[$i], 3); + +if($preview) + hot_ends(); diff --git a/tests/iecs.scad b/tests/iecs.scad new file mode 100644 index 0000000..971bf0a --- /dev/null +++ b/tests/iecs.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/iecs.scad> + +module iecs() + layout([for(i = iecs) iec_flange_h(i)], 10) + rotate(90) + iec_assembly(iecs[$i], 3); + +if($preview) + iecs(); diff --git a/tests/inserts.scad b/tests/inserts.scad new file mode 100644 index 0000000..df39dc8 --- /dev/null +++ b/tests/inserts.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/inserts.scad> + +module inserts() + for(i = [0: len(inserts) -1]) + translate([10 * i, 0]) + insert(inserts[i]); + +if($preview) + inserts(); diff --git a/tests/jack.scad b/tests/jack.scad new file mode 100644 index 0000000..f5bfcc5 --- /dev/null +++ b/tests/jack.scad @@ -0,0 +1,35 @@ +// +// 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 . +// +include <../core.scad> + +use <../vitamins/jack.scad> + +module jacks() { + translate([0, 0]) + jack_4mm("blue",3, "royalblue"); + + translate([20, 0]) + jack_4mm_shielded("brown", 3, "sienna"); + + translate([40, 0]) + post_4mm("red",3); +} + +if($preview) + jacks(); diff --git a/tests/layout.scad b/tests/layout.scad new file mode 100644 index 0000000..be64a27 --- /dev/null +++ b/tests/layout.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../global_defs.scad> +use <../utils/layout.scad> + +diams = [3, 7, 5, 11]; + +module layouts() { + linear_extrude(height = eps) + layout(diams, gap = 1) + circle(d = diams[$i]); +} + +rotate([70, 0, 315]) layouts(); diff --git a/tests/leadnuts.scad b/tests/leadnuts.scad new file mode 100644 index 0000000..1b5251d --- /dev/null +++ b/tests/leadnuts.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/leadnuts.scad> + +module leadnuts() + layout([for(n = leadnuts) leadnut_flange_dia(n)], 5) + leadnut(leadnuts[$i]); + +if($preview) + leadnuts(); diff --git a/tests/leds.scad b/tests/leds.scad new file mode 100644 index 0000000..53f0842 --- /dev/null +++ b/tests/leds.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/leds.scad> + +module leds() + layout([for(l = LEDs) led_diameter(l)], 5) + led(LEDs[$i], ["green", "blue", "red"][$i % 3]); + +if($preview) + leds(); diff --git a/tests/light_strips.scad b/tests/light_strips.scad new file mode 100644 index 0000000..0451630 --- /dev/null +++ b/tests/light_strips.scad @@ -0,0 +1,38 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/light_strips.scad> + +module light_strips() + layout([for(s = light_strips) light_strip_width(s)], 10) + rotate(90) let(light = light_strips[$i], segs = light_strip_segments(light, 260), d = light_strip_clip_depth(light)) { + light_strip(light, segs); + + for(end = [-1, 1]) + translate([end * (light_strip_cut_length(light, segs) / 2 - d / 2), 0]) + rotate([90, 0, 90]) + color("lime") render() + translate_z(-d / 2) + light_strip_clip(light); + } + +if($preview) + light_strips(); diff --git a/tests/linear_bearings.scad b/tests/linear_bearings.scad new file mode 100644 index 0000000..ebe6485 --- /dev/null +++ b/tests/linear_bearings.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/linear_bearings.scad> + +module linear_bearings() + layout([for(b = linear_bearings) 2 * bearing_radius(b)]) + linear_bearing(linear_bearings[$i]); + +if($preview) + linear_bearings(); diff --git a/tests/mains_sockets.scad b/tests/mains_sockets.scad new file mode 100644 index 0000000..b9d7832 --- /dev/null +++ b/tests/mains_sockets.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/mains_sockets.scad> + +module mains_sockets() + layout([for(s = mains_sockets) mains_socket_width(s)], 5) + mains_socket(mains_sockets[$i]); + +if($preview) + mains_sockets(); diff --git a/tests/maths.scad b/tests/maths.scad new file mode 100644 index 0000000..0f36dda --- /dev/null +++ b/tests/maths.scad @@ -0,0 +1,70 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/maths.scad> +use <../utils/annotation.scad> + +tip = [0, 0, 20]; + +module shape() { + cylinder(d1 = 20, d2 = 0, h = tip.z); +} + +t = [10, 20, 30]; +r = [45, 20, 70]; +s = [1, 0.5, 0.75]; + +module maths() { + // + // Translate, rotate and scale the shape + // + translate(t) + rotate(r) + scale(s) + shape(); + // + // Apply the same transformations to the vector position of the tip + // + p = transform(tip, translate(t) * rotate(r) * scale(s)); + // + // Place an arrow where the tip ends up + // + translate(p) + arrow(); + // + // Unit vector pointing at p + // + u = unit(p); + // + // Point arrow in same direction + // + z = [0, 0, 1]; + v = cross(u, z); + a = acos(u * z); + + + l = 20; + rotate(-a, v) + translate_z(l) + vflip() + arrow(l); +} + +rotate(45) + maths(); diff --git a/tests/meter.scad b/tests/meter.scad new file mode 100644 index 0000000..a010603 --- /dev/null +++ b/tests/meter.scad @@ -0,0 +1,39 @@ +// +// 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 . +// +include <../core.scad> + +use <../vitamins/meter.scad> + +module meters() + if($preview) { + meter_assembly(); + + translate([0, meter_bezel_width() + 5]) + vflip() + meter_assembly(); + + translate([0, -meter_bezel_width()]) + rotate([0, 180, 0]) + meter(colour = "blue", value = "123"); + } + else + meter_bezel(); + + +meters(); diff --git a/tests/microswitches.scad b/tests/microswitches.scad new file mode 100644 index 0000000..95ad753 --- /dev/null +++ b/tests/microswitches.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/microswitches.scad> + +module microswitches() + layout([for(i = microswitches) microswitch_length(i)], 5) + microswitch(microswitches[$i]); + +if($preview) + microswitches(); diff --git a/tests/microview.scad b/tests/microview.scad new file mode 100644 index 0000000..7a582be --- /dev/null +++ b/tests/microview.scad @@ -0,0 +1,21 @@ +// +// 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 . +// +use <../vitamins/microview.scad> + +microview(!$preview); diff --git a/tests/modules.scad b/tests/modules.scad new file mode 100644 index 0000000..5bfd1d3 --- /dev/null +++ b/tests/modules.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/modules.scad> + +module modules() + layout([for(m = modules) mod_length(m)], 5) + module_assembly(modules[$i], 3); + +if($preview) + modules(); diff --git a/tests/nuts.scad b/tests/nuts.scad new file mode 100644 index 0000000..4004702 --- /dev/null +++ b/tests/nuts.scad @@ -0,0 +1,51 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> + +module nuts() { + for(nyloc = [false, true]) + translate([0, nyloc ? 20 : 0]) + layout([for(n = nuts) 2 * nut_radius(n)], 5) + nut(nuts[$i], nyloc); + + translate([0, 40]) + layout([for(n = nuts) 2 * nut_radius(n)], 5) let(n = nuts[$i]) { + if(n == M3_nut) + nut(n, brass = true); + + if(n == M2p5_nut) + nut(n, nylon = true); + + if(n == M4_nut) + rotate(-45) + wingnut(M4_wingnut); + + if(n == M6_nut) + nut_and_washer(M6_half_nut, false); + + if(n == M8_nut) + #nut_trap(M8_cap_screw, n, h = 30); + } +} + +if($preview) + nuts(); diff --git a/tests/o_ring.scad b/tests/o_ring.scad new file mode 100644 index 0000000..28ca861 --- /dev/null +++ b/tests/o_ring.scad @@ -0,0 +1,25 @@ +// +// 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 . +// +use <../vitamins/o_ring.scad> + +module o_rings() + O_ring(2.5, 1.6, 3); + +if($preview) + o_rings(); diff --git a/tests/offset.scad b/tests/offset.scad new file mode 100644 index 0000000..bd81d11 --- /dev/null +++ b/tests/offset.scad @@ -0,0 +1,39 @@ +// +// 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 . +// + +include <../core.scad> +use <../utils/offset.scad> + +module shape() + difference() { + cube(40, center = true); + + cube([20, 20, 41], center = true); + } + +module offsets() { + $fn = 20; + + for(x = [-1, 0, 1]) + translate([50 * x, 0]) + offset_3D(3 * x, chamfer_base = true) + shape(); +} + +offsets(); diff --git a/tests/opengrab.scad b/tests/opengrab.scad new file mode 100644 index 0000000..146e023 --- /dev/null +++ b/tests/opengrab.scad @@ -0,0 +1,32 @@ +// +// 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 . +// +include <../core.scad> + +use <../vitamins/opengrab.scad> + +module opengrab_test() { + opengrab_target(); + + rotate(45) + translate_z(opengrab_target_thickness()) + opengrab(); +} + +if($preview) + opengrab_test(); diff --git a/tests/pcbs.scad b/tests/pcbs.scad new file mode 100644 index 0000000..195a617 --- /dev/null +++ b/tests/pcbs.scad @@ -0,0 +1,32 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/d_connectors.scad> +include <../vitamins/pcbs.scad> + +module pcbs() + layout([for(p = pcbs) pcb_width(p)], 15) + translate([0, pcb_length(pcbs[$i]) / 2]) + rotate(90) + pcb_assembly(pcbs[$i], 5 + $i, 3); + +if($preview) + pcbs(); diff --git a/tests/pillars.scad b/tests/pillars.scad new file mode 100644 index 0000000..828efee --- /dev/null +++ b/tests/pillars.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/pillars.scad> + +module pillars() + layout([for(p = pillars) pillar_od(p)], 5) + pillar(pillars[$i]); + +if($preview) + pillars(); diff --git a/tests/polyholes.scad b/tests/polyholes.scad new file mode 100644 index 0000000..fa61b2b --- /dev/null +++ b/tests/polyholes.scad @@ -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 . +// + +include <../core.scad> +use <../vitamins/rod.scad> +include <../vitamins/sheets.scad> + +module polyholes() { + module positions() + for(i = [1 : 10]) { + translate([(i * i + i) / 2 + 3 * i , 8]) + let($r = i / 2) + children(); + + let(d = i + 0.5) + translate([(d * d + d) / 2 + 3 * d, 19]) + let($r = d / 2) + children(); + } + + color(pp1_colour) linear_extrude(height = 3, center = true) + difference() { + square([100, 27]); + + positions() + poly_circle(r = $r); + } + + positions() + rod(d = 2 * $r, l = 8 * $r + 5); + // + // Poly rings + // + ir = 3 / 2; + cir = corrected_radius(ir); + sizes = [1.5, 2, 3, 4]; + for(i = [0 : len(sizes) - 1]) + translate([i * 10, -10]) { + color(pp1_colour) linear_extrude(height = 1) + poly_ring(ir = ir, or = cir + sizes[i] * extrusion_width); + + rod(2 * ir, 3); + } + // + // Drill and slot + // + sheet = Steel06; + translate([10, -30]) + render_2D_sheet(sheet) + difference() { + sheet_2D(sheet, 20, 20, 1); + + translate([0, 5]) + slot(1.5, 6, 0); + + translate([0, -5]) + drill(2, 0); + } +} + +polyholes(); diff --git a/tests/psus.scad b/tests/psus.scad new file mode 100644 index 0000000..9c934e7 --- /dev/null +++ b/tests/psus.scad @@ -0,0 +1,36 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/psus.scad> + +module psus() + layout([for(p = psus) psu_width(p)], 10) let(p = psus[$i]) + rotate(atx_psu(p) ? 0 : 90) { + psu(p); + + psu_screw_positions(p) + translate_z(3) + screw_and_washer(psu_screw(p), 8); + } + +if($preview) + psus(); diff --git a/tests/pulleys.scad b/tests/pulleys.scad new file mode 100644 index 0000000..79212d6 --- /dev/null +++ b/tests/pulleys.scad @@ -0,0 +1,32 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/belts.scad> +include <../vitamins/pulleys.scad> + +module pulleys() + layout([for(p = pulleys) pulley_flange_dia(p)]) + rotate(-45) + pulley_assembly(pulleys[$i]); + +if($preview) + pulleys(); diff --git a/tests/quadrant.scad b/tests/quadrant.scad new file mode 100644 index 0000000..2149f00 --- /dev/null +++ b/tests/quadrant.scad @@ -0,0 +1,29 @@ +// +// 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 . +// + +include <../global_defs.scad> +use <../utils/quadrant.scad> + + +module quadrants() { + linear_extrude(height = eps) + quadrant(10, 4); +} + +rotate([70, 0, 315]) quadrants(); diff --git a/tests/rails.scad b/tests/rails.scad new file mode 100644 index 0000000..f91b950 --- /dev/null +++ b/tests/rails.scad @@ -0,0 +1,48 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/rails.scad> +use <../vitamins/nut.scad> + +sheet = 3; + +module rails() + layout([for(l = rails) carriage_width(rail_carriage(l))], 25) + rotate(-90) { + rail = rails[$i]; + length = rail == MGN15 ? 260 : 200; + screw = rail_screw(rail); + nut = screw_nut(screw); + washer = screw_washer(screw); + + rail_assembly(rail, length, rail_travel(rail, length) / 2); + + rail_screws(rail, length, sheet + nut_thickness(nut, true) + washer_thickness(washer)); + + rail_hole_positions(rail, length, 0) + translate_z(-sheet) + vflip() + nut_and_washer(nut, true); + } + +if($preview) + rails(); diff --git a/tests/ribbon_clamp.scad b/tests/ribbon_clamp.scad new file mode 100644 index 0000000..d797965 --- /dev/null +++ b/tests/ribbon_clamp.scad @@ -0,0 +1,35 @@ +// +// 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 . +// +include <../core.scad> +use <../ribbon_clamp.scad> +use <../vitamins/wire.scad> + +ways = 20; + +module ribbon_clamps() + translate([ribbon_clamp_length(ways) / 2, 0]) + if($preview) { + ribbon_clamp_fastened_assembly(ways, 3); + + ribbon_cable(ways, 100); + } + else + ribbon_clamp(ways); + +ribbon_clamps(); diff --git a/tests/ring_terminals.scad b/tests/ring_terminals.scad new file mode 100644 index 0000000..b46b8b3 --- /dev/null +++ b/tests/ring_terminals.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/ring_terminals.scad> + +module ring_terminals() + layout([for(t = ring_terminals) ringterm_od(t)], 5) + rotate(90) + ring_terminal_assembly(ring_terminals[$i], 3); + +if($preview) + ring_terminals(); diff --git a/tests/rockers.scad b/tests/rockers.scad new file mode 100644 index 0000000..5dd840d --- /dev/null +++ b/tests/rockers.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/rockers.scad> + +module rockers() + layout([for(r = rockers) rocker_flange_w(r)], 5) + rocker(rockers[$i]); + +if($preview) + rockers(); diff --git a/tests/rod.scad b/tests/rod.scad new file mode 100644 index 0000000..f83873a --- /dev/null +++ b/tests/rod.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/linear_bearings.scad> + +use <../vitamins/rod.scad> + +module rods() + layout([for(b = linear_bearings) 2 * bearing_radius(b)]) + rod(bearing_rod_dia(linear_bearings[$i]), 80); + +if($preview) + rods(); diff --git a/tests/round.scad b/tests/round.scad new file mode 100644 index 0000000..dc552b0 --- /dev/null +++ b/tests/round.scad @@ -0,0 +1,42 @@ +// +// 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 . +// + +include <../core.scad> +use <../utils/round.scad> + +module shape() + difference() { + square(40, center = true); + + square([20, 20], center = true); + } + +module rounds() { + linear_extrude(height = eps) + round(or = 4, ir = 2) + shape(); + + + translate([50, 0]) + round_3D(or = 4, ir = 2, chamfer_base = true, $fn = 16) + linear_extrude(height = 40, center = true) + shape(); +} + +rounds(); diff --git a/tests/rounded_cylinder.scad b/tests/rounded_cylinder.scad new file mode 100644 index 0000000..a55b73b --- /dev/null +++ b/tests/rounded_cylinder.scad @@ -0,0 +1,32 @@ +// +// 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 . +// + +include <../global_defs.scad> +use <../utils/rounded_cylinder.scad> + + +module rounded_cylinders() { + linear_extrude(height = eps) + rounded_corner(10, 20, 3, 5); + + translate([30, 10]) + rounded_cylinder(10, 20, 3, 5, 270); +} + +rounded_cylinders(); diff --git a/tests/rounded_polygon.scad b/tests/rounded_polygon.scad new file mode 100644 index 0000000..ad4f786 --- /dev/null +++ b/tests/rounded_polygon.scad @@ -0,0 +1,57 @@ +// +// 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 . +// + +include <../global_defs.scad> +use <../utils/rounded_polygon.scad> +use <../utils/annotation.scad> + +r = 5; +h = 40; +h2 = 20; +h3 = 30; +w = 100; +w2 = 70; +w3 = 30; + +profile = [ + [ -w / 2 + r, r, r], + [ -w / 2 + r / 2, 2 * r + eps, -eps], + [-w2 / 2, h - r, r], + [-w3 / 2, h2 + r,-r], + [ 0, h3 - r, r], + [ w3 / 2, h2 + r,-r], + [ w2 / 2, h - r, r], + [ w / 2 - r / 2, 2 * r + eps, -eps], + [ w / 2 - r, r, r], +]; + +module rounded_polygons() { + tangents = rounded_polygon_tangents(profile); + length = rounded_polygon_length(profile, tangents); + + rotate([70, 0, 315]) + linear_extrude(height = eps) + rounded_polygon(profile, tangents); + + translate([0, -10]) + label(str("perimeter length = ", length), valign = "top", halign = "right"); + +} + +rounded_polygons(); diff --git a/tests/rounded_rectangle.scad b/tests/rounded_rectangle.scad new file mode 100644 index 0000000..8d903cd --- /dev/null +++ b/tests/rounded_rectangle.scad @@ -0,0 +1,30 @@ +// +// 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 . +// + +include <../core.scad> + +module rounded_rectangles() { + linear_extrude(height = eps) + rounded_square([30, 20], 3); + + translate([40, 0]) + rounded_rectangle([30, 20, 10], 3); +} + +rounded_rectangles(); diff --git a/tests/screw_knob.scad b/tests/screw_knob.scad new file mode 100644 index 0000000..28b3058 --- /dev/null +++ b/tests/screw_knob.scad @@ -0,0 +1,37 @@ +// +// 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 . +// +include <../core.scad> +use <../screw_knob.scad> + +include <../vitamins/screws.scad> + +screws = [M3_hex_screw, M4_hex_screw]; + +module do_screw_knob(screw) + if($preview) + screw_knob_assembly(screw, 16); + else + screw_knob(screw); + +module screw_knobs() + for(i = [0 : len(screws) - 1]) + translate([i * 30, 0]) + do_screw_knob(screws[i]); + +screw_knobs(); diff --git a/tests/screws.scad b/tests/screws.scad new file mode 100644 index 0000000..37b22be --- /dev/null +++ b/tests/screws.scad @@ -0,0 +1,37 @@ +// +// 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 . +// +include <../core.scad> + +include <../vitamins/screws.scad> + +module screws() +for(y = [0 : len(screw_lists) -1]) + for(x = [0 : len(screw_lists[y]) -1]) { + screw = screw_lists[y][x]; + if(screw) { + length = screw_max_thread(screw) + ? screw_longer_than(screw_max_thread(screw) + 5) + : screw_head_type(screw) == hs_grub ? 6 : 30; + translate([x * 20, y * 20]) + screw(screw, length); + } + } + +if($preview) + screws(); diff --git a/tests/sealing_strip.scad b/tests/sealing_strip.scad new file mode 100644 index 0000000..215f43b --- /dev/null +++ b/tests/sealing_strip.scad @@ -0,0 +1,26 @@ +// +// 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 . +// +include <../core.scad> +use <../vitamins/sealing_strip.scad> + +module sealing_strip_test() + sealing_strip(100); + +if($preview) + sealing_strip_test(); diff --git a/tests/sector.scad b/tests/sector.scad new file mode 100644 index 0000000..da05bb1 --- /dev/null +++ b/tests/sector.scad @@ -0,0 +1,29 @@ +// +// 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 . +// + +include <../global_defs.scad> +use <../utils/sector.scad> + + +module sectors() { + linear_extrude(height = eps) + sector(50, 45, 180); +} + +rotate([70, 0, 315]) sectors(); diff --git a/tests/sheets.scad b/tests/sheets.scad new file mode 100644 index 0000000..c7fcdbb --- /dev/null +++ b/tests/sheets.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/sheets.scad> + +width = 30; + +module sheets() + layout([for(s = sheets) width], 5) + render_sheet(sheets[$i]) sheet(sheets[$i], width, width, 2); + +if($preview) + sheets(); diff --git a/tests/socket_box.scad b/tests/socket_box.scad new file mode 100644 index 0000000..851b8d0 --- /dev/null +++ b/tests/socket_box.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +$explode = 1; +include <../core.scad> +use <../utils/layout.scad> +include <../vitamins/mains_sockets.scad> +use <../socket_box.scad> +module socket_boxes() + layout([for(s = mains_sockets) mains_socket_width(s)], 20) + if($preview) + socket_box_fastened_assembly(mains_sockets[$i], 3); + else + socket_box_stl(mains_sockets[$i]); + +socket_boxes(); diff --git a/tests/spades.scad b/tests/spades.scad new file mode 100644 index 0000000..b76c8a6 --- /dev/null +++ b/tests/spades.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/spades.scad> + +module spades() + layout([for(s = spades) spade_w(s)], 5) + spade(spades[$i], 10); + +if($preview) + spades(); diff --git a/tests/sphere.scad b/tests/sphere.scad new file mode 100644 index 0000000..d4b531f --- /dev/null +++ b/tests/sphere.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> + +r = 20; + +verts = [4, 8, 12, 16, 20, 24, 28, 32]; + +module spheres() + for(i = [0: len(verts)-1], $fn =verts[i]) + translate([i * 2 * r, 0]) + sphere(r); + + +spheres(); diff --git a/tests/spools.scad b/tests/spools.scad new file mode 100644 index 0000000..d39c246 --- /dev/null +++ b/tests/spools.scad @@ -0,0 +1,31 @@ +// +// 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 . +// + +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/spools.scad> + +module spools() + layout([for(s = spools) spool_height(s)], 100) + rotate([90, 0, 90]) + spool(spools[$i]); + +if($preview) + spools(); diff --git a/tests/springs.scad b/tests/springs.scad new file mode 100644 index 0000000..8d9c8ee --- /dev/null +++ b/tests/springs.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/springs.scad> + +module springs() + layout([for(s = springs) spring_od2(s)], 5) + comp_spring(springs[$i]); + +if($preview) + springs(); diff --git a/tests/ssrs.scad b/tests/ssrs.scad new file mode 100644 index 0000000..8636cce --- /dev/null +++ b/tests/ssrs.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/ssrs.scad> + +module ssrs() + layout([for(s = ssrs) ssr_length(s)], 15) + ssr_assembly(ssrs[$i], M4_cap_screw, 3); + +if($preview) + ssrs(); diff --git a/tests/stepper_motors.scad b/tests/stepper_motors.scad new file mode 100644 index 0000000..ef13bc1 --- /dev/null +++ b/tests/stepper_motors.scad @@ -0,0 +1,34 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/stepper_motors.scad> + +module stepper_motors() + layout([for(s = stepper_motors) NEMA_width(s)], 5) { + rotate(180) + NEMA(stepper_motors[$i]); + + NEMA_screws(stepper_motors[$i], M3_pan_screw); + } + +if($preview) + stepper_motors(); diff --git a/tests/strap_handle.scad b/tests/strap_handle.scad new file mode 100644 index 0000000..d14aa4b --- /dev/null +++ b/tests/strap_handle.scad @@ -0,0 +1,34 @@ +// +// 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 . +// +include <../core.scad> +use <../strap_handle.scad> + +length = 150; + +module strap_handles() + if($preview) + strap_assembly(length); + else { + strap(length); + + translate([0, 30]) + strap_end(); + } + +strap_handles(); diff --git a/tests/sweep.scad b/tests/sweep.scad new file mode 100644 index 0000000..900199f --- /dev/null +++ b/tests/sweep.scad @@ -0,0 +1,53 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/sweep.scad> +use <../utils/maths.scad> +use <../utils/bezier.scad> + +L_points = [[0, 5, 0], [ 2, 5, 0], [2, 2, 0], [10, 2, 0], [10, 0, 0], [0, 0, 0]]; + +rad = 90; +loop = circle_points(rad, $fn = 180); + +loop_x = transform_points(loop, rotate([90, -90, $t * 360])); + +loop_y = transform_points(loop, rotate([0, -90, $t * 360])); + +loop_z = transform_points(loop, rotate([$t * 360, 0, 0])); + +sweep(loop_z, L_points, loop = true); + +sweep(loop_x, L_points, loop = true); + +sweep(loop_y, L_points, loop = true); + + +knot = [ for(i=[0:.2:359]) + [ (19*cos(3*i) + 40)*cos(2*i), + (19*cos(3*i) + 40)*sin(2*i), + 19*sin(3*i) ] ]; + +sweep(knot, L_points, loop = true, twist = 0); + +p = transform_points([[0,0,0], [20,0,5], [10,30,4], [0,0,0], [0,0,20]], scale(10)); +n = 100; +path = bezier_path(p, n); + +rotate(45) sweep(path, circle_points(5, $fn = 64)); diff --git a/tests/teardrops.scad b/tests/teardrops.scad new file mode 100644 index 0000000..9d62cd6 --- /dev/null +++ b/tests/teardrops.scad @@ -0,0 +1,43 @@ +// +// 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 . +// + +include <../core.scad> + +module teardrops() { + color(pp1_colour) + rotate([90, 0, -45]) + linear_extrude(height = 3) + difference() { + square(40); + + translate([10, 10]) + teardrop(h = 0, r = 3); + + translate([10, 20]) + teardrop_plus(h = 0, r = 3); + + translate([20, 30]) + tearslot(h = 0, r = 3, w = 10); + + translate([30, 15]) + vertical_tearslot(h = 0, r =3, l = 10); + } +} + +teardrops(); diff --git a/tests/toggles.scad b/tests/toggles.scad new file mode 100644 index 0000000..f87199d --- /dev/null +++ b/tests/toggles.scad @@ -0,0 +1,30 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/toggles.scad> + +module toggles() + layout([for(t = toggles) toggle_width(t)], 16) + toggle(toggles[$i], 3); + +if($preview) + toggles(); diff --git a/tests/transformers.scad b/tests/transformers.scad new file mode 100644 index 0000000..19db222 --- /dev/null +++ b/tests/transformers.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/transformers.scad> + +module transformers() + layout([for(t = transformers) tx_depth(t)], 10) + rotate(90) + transformer(transformers[$i]); + +if($preview) + transformers(); diff --git a/tests/tube.scad b/tests/tube.scad new file mode 100644 index 0000000..6e7745d --- /dev/null +++ b/tests/tube.scad @@ -0,0 +1,32 @@ +// +// 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 . +// + +include <../global_defs.scad> +use <../utils/tube.scad> + + +module tubes() { + linear_extrude(height = eps) + ring(10, 8); + + translate([50, 10]) + tube(10, 8, 30); +} + +tubes(); diff --git a/tests/tubings.scad b/tests/tubings.scad new file mode 100644 index 0000000..77e6513 --- /dev/null +++ b/tests/tubings.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/tubings.scad> + +module tubings() + layout([for(t = tubings) tubing_od(t)], 10) + tubing(tubings[$i]); + +if($preview) + tubings(); diff --git a/tests/variacs.scad b/tests/variacs.scad new file mode 100644 index 0000000..65c7cf6 --- /dev/null +++ b/tests/variacs.scad @@ -0,0 +1,31 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +include <../vitamins/variacs.scad> + +module variacs() + layout([for(v = variacs) 2 * (variac_bulge_dia(v) - variac_diameter(v) / 2)], 25) + rotate(-90) + variac(variacs[$i]); + +if($preview) + variacs(); diff --git a/tests/veroboard.scad b/tests/veroboard.scad new file mode 100644 index 0000000..9deee5b --- /dev/null +++ b/tests/veroboard.scad @@ -0,0 +1,48 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/screws.scad> +use <../vitamins/veroboard.scad> + +z_cable_ways = 20; + +z_vb = ["z_vb", "z_bed_terminal", 5, z_cable_ways / 2 + 12, inch(0.1), false, M3_dome_screw, + [[2,2],[2,-3]], [], [5, 7, 9], + [ + [3, z_cable_ways / 4 + 5.5, 0, "term254", z_cable_ways / 2, [1, 3]], + [0.5, z_cable_ways / 4 + 5.5, 90, "transition", z_cable_ways / 2, [1, 3]], + ], + [ + [[0,1,3], 6], [[0,1,3], 8], [[0,1,3],[10 : 6 + z_cable_ways / 2 - 1]], + ] + ]; + +module veroboard_test() translate([vero_length(z_vb) / 2, vero_width(z_vb) / 2]) { + vflip() + veroboard_assembly(z_vb, 12, 3); + + translate([30, 0]) + rotate(180) + veroboard_assembly(z_vb, 12, 3); +} + +if($preview) + veroboard_test(); diff --git a/tests/washers.scad b/tests/washers.scad new file mode 100644 index 0000000..a18ecb4 --- /dev/null +++ b/tests/washers.scad @@ -0,0 +1,47 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/washers.scad> + +function penny_diameter(w) = let(p = penny_washer(w)) washer_diameter(p ? p : w); + +module washers() + layout([for(w = washers) penny_diameter(w)], 2) let(w = washers[$i]) { + star_washer(w); + + if(spring_washer_thickness(w)) + translate([0, 20]) + let($explode = 1) + spring_washer(w); + + translate([0, 40]) + washer(w); + + if(penny_washer(w)) + translate([0, 65]) + penny_washer(w); + + translate([0, 90]) + printed_washer(w); + } + +if($preview) + washers(); diff --git a/tests/zipties.scad b/tests/zipties.scad new file mode 100644 index 0000000..cafb5cd --- /dev/null +++ b/tests/zipties.scad @@ -0,0 +1,29 @@ +// +// 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 . +// +include <../core.scad> +use <../utils/layout.scad> + +include <../vitamins/zipties.scad> + +module zipties() + layout([for(z = zipties) 9], 10) + ziptie(zipties[$i], 5); + +if($preview) + zipties(); diff --git a/times.txt b/times.txt new file mode 100644 index 0000000..313fdb2 --- /dev/null +++ b/times.txt @@ -0,0 +1,92 @@ +{ + "tests/annotation.scad": 2.104, + "tests/ball_bearings.scad": 2.148, + "tests/batteries.scad": 3.81, + "tests/belts.scad": 3.212, + "tests/bezier.scad": 5.746, + "tests/blowers.scad": 2.133, + "tests/box.scad": 14.312, + "tests/bulldogs.scad": 2.465, + "tests/buttons.scad": 2.261, + "tests/butt_box.scad": 8.325, + "tests/cable_grommets.scad": 2.128, + "tests/cable_strips.scad": 2.148, + "tests/carriers.scad": 2.259, + "tests/clip.scad": 5.751, + "tests/components.scad": 3.266, + "tests/corner_block.scad": 17.288, + "tests/displays.scad": 1.936, + "tests/dogbones.scad": 1.543, + "tests/door_hinge.scad": 1.622, + "tests/door_latch.scad": 3.21, + "tests/d_connectors.scad": 1.743, + "tests/fans.scad": 1.963, + "tests/fan_guard.scad": 1.861, + "tests/fillet.scad": 1.468, + "tests/fixing_block.scad": 4.495, + "tests/foot.scad": 1.54, + "tests/fuseholder.scad": 1.629, + "tests/global.scad": 1.445, + "tests/handle.scad": 2.211, + "tests/hanging_hole.scad": 2.239, + "tests/hot_ends.scad": 2.875, + "tests/iecs.scad": 1.608, + "tests/inserts.scad": 1.462, + "tests/jack.scad": 2.241, + "tests/layout.scad": 1.708, + "tests/leadnuts.scad": 1.534, + "tests/leds.scad": 1.514, + "tests/light_strips.scad": 1.678, + "tests/linear_bearings.scad": 1.578, + "tests/maths.scad": 2.017, + "tests/meter.scad": 2.135, + "tests/microswitches.scad": 1.77, + "tests/microview.scad": 2.88, + "tests/modules.scad": 2.25, + "tests/nuts.scad": 1.933, + "tests/offset.scad": 12.661, + "tests/opengrab.scad": 1.69, + "tests/o_ring.scad": 1.826, + "tests/pcbs.scad": 5.944, + "tests/pillars.scad": 1.908, + "tests/polyholes.scad": 3.002, + "tests/psus.scad": 6.242, + "tests/pulleys.scad": 5.971, + "tests/quadrant.scad": 2.113, + "tests/rails.scad": 2.865, + "tests/ribbon_clamp.scad": 5.174, + "tests/ring_terminals.scad": 2.097, + "tests/rockers.scad": 1.49, + "tests/rod.scad": 2.082, + "tests/round.scad": 352.238, + "tests/rounded_cylinder.scad": 2.155, + "tests/rounded_polygon.scad": 1.951, + "tests/rounded_rectangle.scad": 1.86, + "tests/screws.scad": 2.783, + "tests/screw_knob.scad": 4.461, + "tests/sealing_strip.scad": 1.709, + "tests/sector.scad": 2.029, + "tests/sheets.scad": 1.907, + "tests/socket_13A.scad": 9.275, + "tests/spades.scad": 2.28, + "tests/spheres.scad": 1.569, + "tests/spools.scad": 2.278, + "tests/springs.scad": 3.446, + "tests/ssrs.scad": 3.371, + "tests/stepper_motors.scad": 3.43, + "tests/strap_handle.scad": 3.182, + "tests/sweep.scad": 4.344, + "tests/teardrops.scad": 2.764, + "tests/toggles.scad": 3.929, + "tests/transformers.scad": 2.852, + "tests/tube.scad": 2.773, + "tests/tubings.scad": 3.01, + "tests/variacs.scad": 3.045, + "tests/veroboard.scad": 3.791, + "tests/washers.scad": 3.706, + "tests/zipties.scad": 2.501, + "tests/bom.scad": 2.328, + "tests/sphere.scad": 2.092, + "tests/socket_box.scad": 21.617, + "tests/mains_sockets.scad": 15.204 +} \ No newline at end of file diff --git a/utils/annotation.scad b/utils/annotation.scad new file mode 100644 index 0000000..1ca4a7c --- /dev/null +++ b/utils/annotation.scad @@ -0,0 +1,40 @@ +// +// 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 . +// +include <../core.scad> +// +//! Annotation used in this documentation + +module label(str, scale = 0.25, valign = "baseline", halign = "left") //! Draw text that always faces the camera + color("black") + %rotate($vpr != [0, 0, 0] ? $vpr : [70, 0, 315]) + linear_extrude(height = eps) + scale(scale) + text(str, valign = valign, halign = halign); + +module arrow(length = 20) { //! Draw an arrow that faces downwards + d = length / 20; + head_r = 1.5 * d; + + color("grey") %union() { + translate_z(head_r) + cylinder(d = d, h = length - head_r, $fn = 32); + + cylinder(r1 = 0, r2 = head_r, h = head_r); + } +} diff --git a/utils/bezier.scad b/utils/bezier.scad new file mode 100644 index 0000000..711f23a --- /dev/null +++ b/utils/bezier.scad @@ -0,0 +1,57 @@ +// +// 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 . +// + +// +//! Bezier curves and function to get and adjust the length or minimum z point. +// +include <../global_defs.scad> + +function bezier(t, v) = //! Returns a point at distance ```t``` [0 - 1] along the curve with control points ```v``` + (len(v) > 2) ? bezier(t, [for (i = [0 : len(v) - 2]) v[i] * (1 - t) + v[i + 1] * (t)]) + : v[0] * (1 - t) + v[1] * (t); + +function bezier_path(v, steps = 100) = //! Returns a Bezier path from control points ```v``` with ```steps``` segments + [for(i = [0 : steps], t = i / steps) bezier(t, v)]; + +function bezier_length(v, delta = 0.01, t = 0, length = 0) = //! Calculate the length of a Bezier curve from control points ```v``` + t > 1 ? length + : bezier_length(v, delta, t + delta, length + norm(bezier(t, v) - bezier(t + delta, v))); + +function adjust_bezier(v, r) = + let(extension = (v[1] - v[0]) * (r - 1)) + [v[0], v[1] + extension, v[2] + extension, v[3]]; + +function adjust_bezier_length(v, l, eps = 0.001, r1 = 1.0, r2 = 1.5, l1, l2) = //! Adjust Bezier control points ```v``` to get the required curve length ```l``` + let(l1 = l1 != undef ? l1 : bezier_length(adjust_bezier(v, r1)), + l2 = l2 != undef ? l2 : bezier_length(adjust_bezier(v, r2)) + ) abs(l1 - l) < eps ? adjust_bezier(v, r1) + : let(r = r1 + (l - l1) * (r2 - r1) / (l2 - l1)) + abs(r - r1) < abs(r - r2) ? adjust_bezier_length(v, l, eps, r, r1, undef, l1) + : adjust_bezier_length(v, l, eps, r, r2, undef, l2); + +function bezier_min_z(v, steps = 100, z = inf, i = 0) = //! Calculate the minimum z coordinate of a Bezier curve from control points ```v``` + i <= steps ? bezier_min_z(v, steps, min(z, bezier(i / steps, v).z), i + 1) : z; + +function adjust_bezier_z(v, z, eps = 0.001, r1 = 1, r2 = 1.5, z1, z2) = //! Adjust Bezier control points ```v``` to get the required minimum ```z``` + let(z1 = z1 != undef ? z1 : bezier_min_z(adjust_bezier(v, r1)), + z2 = z2 != undef ? z2 : bezier_min_z(adjust_bezier(v, r2)) + ) abs(z1 - z) < eps ? adjust_bezier(v, r1) + : let(r = r1 + (z - z1) * (r2 - r1) / (z2 - z1)) + abs(r - r1) < abs(r - r2) ? adjust_bezier_z(v, z, eps, r, r1, undef, z1) + : adjust_bezier_z(v, z, eps, r, r2, undef, z2); diff --git a/utils/core/bom.scad b/utils/core/bom.scad new file mode 100644 index 0000000..bf080e1 --- /dev/null +++ b/utils/core/bom.scad @@ -0,0 +1,112 @@ +// +// 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 . +// + +// +//! Bill Of Materials generation via echo and the ```bom.py``` script. Also handles exploded assembly views and posing. Assembly instructions can precede the module +//! definition that makes the assembly. +//! +//! The example below shows how to define a vitamin and incorporate it into an assembly with sub-assemblies and make an exploded view. The resulting flat BOM is shown but +//! heirachical BOMs are also generated for real projects. +// +function bom_mode(n = 1) = $_bom >= n && (is_undef($on_bom) || $on_bom); //! Current BOM mode, 0 = none, 1 = printed and routed parts and assemblies, 2 includes vitamins as well +function exploded() = is_undef($exploded_parent) ? $exploded : 0; //! Returns the value of ```$exploded``` if it is defined, else ```0``` +function show_supports() = !$preview || exploded(); //! True if printed support material should be shown + +module no_explode() let($exploded_parent = true) children(); //! Prevent children being exploded +module no_pose() let($posed = true) children(); //! Force children not to be posed even if parent is + +module explode(d, explode_children = false, offset = [0,0,0]) { //! Explode children by specified Z distance or vector ```d```, option to explode grand children + v = is_list(d) ? d : [0, 0, d]; + o = is_list(offset) ? offset : [0, 0, offset]; + if($exploded && is_undef($exploded_parent)) { + translate(o) // Draw the line first in case the child is transparent + hull() { + sphere(0.2); + + translate(v * $exploded) + sphere(0.2); + } + + translate(v * $exploded) + let($exploded_parent = explode_children ? undef : true) + children(); + } + else + children(); +} + +module pose(a = [55, 0, 25], t = [0, 0, 0], exploded = undef) //! Pose an STL or assembly for rendering to png by specifying rotation ```a``` and translation ```t```, ```exploded = true for``` just the exploded view or ```false``` for unexploded only. + if(is_undef($pose) || !is_undef($posed) || (!is_undef(exploded) && exploded != !!exploded())) + children(); + else + let($posed = true) // only pose the top level + rotate([55, 0, 25]) + rotate([-a.x, 0, 0]) + rotate([0, -a.y, 0]) + rotate([0, 0, -a.z]) + translate(-t) + children(); + + +module assembly(name) { //! Name an assembly that will appear on the BOM, there needs to a module named ```_assembly``` to make it + if(bom_mode()) + echo(str("~", name, "_assembly{")); + + no_pose() + if(is_undef($child_assembly)) + let($child_assembly = true) + children(); + else + no_explode() + children(); + + if(bom_mode()) + echo(str("~}", name, "_assembly")); +} + +module stl(name) { //! Name an stl that will appear on the BOM, there needs to a module named ```_stl``` to make it + if(bom_mode()) + echo(str("~", name, ".stl")); +} + +module dxf(name) { //! Name a dxf that will appear on the BOM, there needs to a module named ```_dxf``` to make it + if(bom_mode()) + echo(str("~", name, ".dxf")); +} + +function value_string(value) = is_string(value) ? str("\"", value, "\"") : str(value); //! Convert ```value``` to a string or quote it if it is already a string + +function arg(value, default, name = "") = //! Create string for arg if not default, helper for ```vitamin()``` + value == default ? "" + : name ? str(", ", name, " = ", value_string(value)) + : str(", ", value_string(value)); + +module vitamin(description) { //! Describe a vitamin for the BOM entry and precede it with a module call that creates it, eg. "wigit(42): Type 42 widget" + if(bom_mode(2)) + echo(str("~", description, !is_undef($hidden) ? " - not shown" : "")); +} + +module not_on_bom(on = false) //! Specify the following child parts are not on the BOM, for example when they are on a PCB that comes assembled + let($on_bom = on) + children(); + +module hidden() //! Make item invisible, except on the BOM + scale(1 / sqr(1024)) + let($hidden = true) + children(); diff --git a/utils/core/clip.scad b/utils/core/clip.scad new file mode 100644 index 0000000..1b526d2 --- /dev/null +++ b/utils/core/clip.scad @@ -0,0 +1,49 @@ +// +// 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 . +// + +// +//! Construct arbirarily large box to partition 3D space and clip objects, useful for creating cross sections to see the inside when debugging. +//! +//! Original version by Doug Moen on the OpenSCAD forum +// +// +module box(xmin, ymin, zmin, xmax, ymax, zmax) //! Construct a box given its bounds + polyhedron( + [[xmin, ymin, zmin], // 0 + [xmin, ymin, zmax], // 1 + [xmin, ymax, zmin], // 2 + [xmin, ymax, zmax], // 3 + [xmax, ymin, zmin], // 4 + [xmax, ymin, zmax], // 5 + [xmax, ymax, zmin], // 6 + [xmax, ymax, zmax]], // 7 + [[7,5,1,3], // top + [2,0,4,6], // bottom + [5,4,0,1], // front + [3,2,6,7], // back + [5,7,6,4], // right + [0,2,3,1]] // left + ); + +module clip(xmin = -inf, ymin = -inf, zmin = -inf, xmax = inf, ymax = inf, zmax = inf) //! Clip child to specified boundaries + render() intersection() { + children(); + + box(xmin, ymin, zmin, xmax, ymax, zmax); + } diff --git a/utils/core/global.scad b/utils/core/global.scad new file mode 100644 index 0000000..32b371c --- /dev/null +++ b/utils/core/global.scad @@ -0,0 +1,64 @@ +// +// 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 . +// + +// +//! Global constants, functions and modules. This file is used directly or indirectly in every scad file. +// +include <../../global_defs.scad> + +function sqr(x) = x * x; //! Returns the square of ```x``` +function inch(x) = x * 25.4; //! Inch to mm conversion +function echoit(x) = echo(x) x; //! Echo expression and return it, useful for debugging +function in(list, x) = !!len([for(v = list) if(v == x) true]); //! Returns true if ```x``` is an element in the ```list``` +function Len(x) = is_list(x) ? len(x) : 0; //! Returns the length of a list or 0 if ```x``` is not a list +function r2sides(r) = $fn ? $fn : ceil(max(min(360/ $fa, r * 2 * PI / $fs), 5)); //! Replicates the OpenSCAD logic to calculate the number of sides from the radius +function r2sides4n(r) = floor((r2sides(r) + 3) / 4) * 4; //! Round up the number of sides to a multiple of 4 to ensure points land on all axes + +module translate_z(z) translate([0, 0, z]) children(); //! Shortcut for Z only translations +module vflip() rotate([180, 0, 0]) children(); //! Invert children by doing a 180 flip around the X axis +module ellipse(xr, yr) scale([1, yr / xr]) circle4n(xr); //! Draw an ellipse + +module extrude_if(h, center = true) //! Extrudes 2D object to 3D when ```h``` is nonzero, otherwise leaves it 2D + if(h) + linear_extrude(height = h, center = center) // 3D + children(); + else + children(); // 2D + +module circle4n(r, d = undef) { //! Circle with multiple of 4 vertices + R = is_undef(d) ? r : d / 2; + circle(R, $fn = r2sides4n(R)); +} + +module semi_circle(r, d = undef) //! A semi circle in the positive Y domain + intersection() { + R = is_undef(d) ? r : d / 2; + circle4n(R); + + sq = R + 1; + translate([-sq, 0]) + square([2 * sq, sq]); + } + +include +include +include +include +include +include diff --git a/utils/core/polyholes.scad b/utils/core/polyholes.scad new file mode 100644 index 0000000..e57b087 --- /dev/null +++ b/utils/core/polyholes.scad @@ -0,0 +1,79 @@ +// +// 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 . +// + +// +//! A method of making 3D printed holes come out the right size regardless of the printer, providing +//! it gets the linear dimensions right. See +//! +//! The module provides `poly_circle()`, `poly_cylinder()` and `poly_ring()` that is useful for making printed washers and pillars. +// +function sides(r) = max(round(4 * r), 3); //! Optimium number of sides for specified radius +function corrected_radius(r, n = 0) = r / cos(180 / (n ? n : sides(r))); //! Adjusted radius to make flats lie on the circle +function corrected_diameter(d, n = 0) = d / cos(180 / (n ? n : sides(d / 2))); //! Adjusted diameter to make flats lie on the circle + +module poly_circle(r, sides = 0) { //! Make a circle adjusted to print the correct size + n = sides ? sides : sides(r); + circle(r = corrected_radius(r,n), $fn = n); +} + +module poly_cylinder(r, h, center = false, sides = 0) //! Make a cylinder adjusted to print the correct size + extrude_if(h, center) + poly_circle(r, sides); + +module poly_ring(or, ir) { //! Make a 2D ring adjusted to have the correct internal radius + cir = corrected_radius(ir); + filaments = floor((or - cir) / extrusion_width); + if(filaments > 3) + difference() { + circle(or); + + poly_circle(ir); + } + else + if(filaments >= 2) + difference() { + offset(or - cir) + poly_circle(ir); + + poly_circle(ir); + } + else + difference() { + poly_circle(or); + + offset(-squeezed_wall) + poly_circle(or); + } +} + +module drill(r, h = 100) //! Make a cylinder for drilling holes suitable for CNC routing, set h = 0 for circle + extrude_if(h) + circle(r = corrected_radius(r, r2sides(r))); +// +// Horizontal slot +// +module slot(r, l, h = 100) //! Make a horizontal slot suitable for CNC routing, set h = 0 for 2D version + extrude_if(h) + hull() { + translate([l / 2,0]) + drill(r, 0); + + translate([-l / 2,0]) + drill(r, 0); + } diff --git a/utils/core/rounded_rectangle.scad b/utils/core/rounded_rectangle.scad new file mode 100644 index 0000000..123c5d1 --- /dev/null +++ b/utils/core/rounded_rectangle.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +//! Rectangle with rounded corners. +// +module rounded_square(size, r, center = true) //! Like ```square()``` but with with rounded corners +{ + $fn = r2sides4n(r); + offset(r) offset(-r) square(size, center = center); +} + +module rounded_rectangle(size, r, center = true, xy_center = true) //! Like ```cube()``` but corners rounded in XY plane and separate centre options for xy and z. +{ + linear_extrude(height = size[2], center = center) + rounded_square([size[0], size[1]], r, xy_center); +} diff --git a/utils/core/sphere.scad b/utils/core/sphere.scad new file mode 100644 index 0000000..31459c4 --- /dev/null +++ b/utils/core/sphere.scad @@ -0,0 +1,28 @@ +// +// 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 . +// + +//! Redefines `sphere()` to always have a vertex on all six half axes I.e. vertices at the poles and the equator and `$fn` a multiple of four. +//! This ensures `hull` and `minkowski` results have the correct dimensions when spheres are placed at the corners. + +module sphere(r = 1, d = undef) { //! Override ```sphere``` so that has vertices on all three axes. Has the advantage of giving correct dimensions when hulled + R = is_undef(d) ? r : d / 2; + rotate_extrude($fn = r2sides4n(R)) + rotate(-90) + semi_circle(R); +} diff --git a/utils/core/teardrops.scad b/utils/core/teardrops.scad new file mode 100644 index 0000000..74821a0 --- /dev/null +++ b/utils/core/teardrops.scad @@ -0,0 +1,53 @@ +// +// 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 . +// + +// +//! For making horizontal holes that don't need support material. +//! Small holes can get away without it, but they print better with truncated teardrops. +// +module teardrop(h, r, center = true, truncate = true) //! For making horizontal holes that don't need support material, set ```truncate = false``` to make traditional RepRap teardrops that don't even need bridging + render(convexity = 5) + extrude_if(h, center) + hull() { + circle4n(r); + + if(truncate) + translate([0, r / 2]) + square([2 * r * (sqrt(2) - 1), r], center = true); + else + polygon([[0, 0], [eps, 0], [0, r * sqrt(2)]]); + } + +module teardrop_plus(h, r, center = true, truncate = true) //! Slightly bigger teardrop to allow for the 3D printing staircase effect + teardrop(h, r + layer_height / 4, center, truncate); + +module tearslot(h, r, w, center = true) //! A horizontal slot that doesn't need support material + extrude_if(h, center) + hull() { + translate([-w/2,0,0]) teardrop(r = r, h = 0); + translate([ w/2,0,0]) teardrop(r = r, h = 0); + } + +module vertical_tearslot(h, r, l, center = true) //! A vertical slot that doesn't need support material + extrude_if(h, center) + hull() { + translate([0, l / 2]) teardrop(0, r, true); + translate([0, -l / 2]) + circle4n(r); + } diff --git a/utils/dogbones.scad b/utils/dogbones.scad new file mode 100644 index 0000000..3231fe4 --- /dev/null +++ b/utils/dogbones.scad @@ -0,0 +1,46 @@ +// +// 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 . +// + +// +//! When square holes are cut with a CNC bit they get rounded corners. If it is important that +//! a square cornered part fits in the hole then circles are placed in the corners making a bone shape. +// +include <../core.scad> + +module dogbone_square(size, r = cnc_bit_r, center = true) //! Square with circles at the corners +{ + union() { + square(size, center = center); + + if(r > 0) { + origin = center ? [0, 0] : size / 2; + offset = r / sqrt(2); + + for(x = [-1, 1], y = [-1, 1]) + translate(origin + [x * (size.x / 2 - offset), y * (size.y / 2 - offset)]) + drill(r, 0); + } + } +} + +module dogbone_rectangle(size, r = cnc_bit_r, center = true, xy_center = true) //! Rectangle with cylinders at the corners +{ + extrude_if(h = size.z, center = center) + dogbone_square([size.x, size.y], r, xy_center); +} diff --git a/utils/fillet.scad b/utils/fillet.scad new file mode 100644 index 0000000..99359c2 --- /dev/null +++ b/utils/fillet.scad @@ -0,0 +1,32 @@ +// +// 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 . +// + +// +//! Rounded fillet for adding to corners. +// +include <../core.scad> + +module fillet(r, h, center = false) //! Fillet with specified radius and height + extrude_if(h, center = center) + difference() { + translate([-eps, -eps, 0]) + square(r + eps); + + circle(r + eps); + } diff --git a/utils/hanging_hole.scad b/utils/hanging_hole.scad new file mode 100644 index 0000000..cb456be --- /dev/null +++ b/utils/hanging_hole.scad @@ -0,0 +1,64 @@ +// +// 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 . +// + +// +//! Method to print holes in mid air. See +// +include <../core.scad> + +module hanging_hole(z, ir, h = 100, h2 = 100) { //! Hole radius ```ir``` hanging at the specified ```z``` value above a void who's shape is given by a 2D child + module polyhole(r, h, n = 8) { + if(h > 0) + rotate(180 / n) { + poly_cylinder(r = r, h = layer_height, sides = n); + + translate_z(layer_height) + if(2 * n <= sides(r)) + polyhole(r - eps, h - layer_height, n * 2); + else + poly_cylinder(r - eps, h - layer_height); + } + } + assert(z % layer_height == 0, str(z)); + infill_angle = z % (2 * layer_height) ? -45 : 45; + below = min(z + eps, h2); + big = 1000; + + render(convexity = 3) translate_z(z) + union() { + translate_z(2 * layer_height) + polyhole(ir - eps, h - 2 * layer_height); + + difference() { + translate_z(-below) + linear_extrude(height = below + 2 * layer_height) + children(); + + rotate(infill_angle) + for(side = [-1, 1]) { + translate([side * (ir + big), 0, big + layer_height]) + cube(2 * big, center = true); + + translate([0, side * (ir + big), big]) + cube(2 * big, center = true); + + } + } + } +} diff --git a/utils/layout.scad b/utils/layout.scad new file mode 100644 index 0000000..8945427 --- /dev/null +++ b/utils/layout.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +//! Layout objects in a line with equal gaps given a vector of their widths. +// +include <../global_defs.scad> + +function layout_offset(widths, i, gap = 2) = //! Calculate the offset for the ```i```th item + i == 0 ? widths[0] / 2 + : layout_offset(widths, i - 1, gap) + widths[i - 1] / 2 + gap + widths[i] / 2; + +module layout(widths, gap = 2, no_offset = false) //! Layout children passing ```$i``` + translate([no_offset ? -widths[0] / 2 : 0, 0]) + for($i = [0 : len(widths) - 1]) + translate([layout_offset(widths, $i, gap), 0]) + children(); diff --git a/utils/maths.scad b/utils/maths.scad new file mode 100644 index 0000000..97b6bb2 --- /dev/null +++ b/utils/maths.scad @@ -0,0 +1,76 @@ +// +// 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 . +// + +// +//! Maths utilities for minapulating vectors and matrices. +// +function sqr(x) = x * x; + +function translate(v) = let(u = is_list(v) ? len(v) == 2 ? [v.x, v.y, 0] //! Generate a 4x4 translation matrix, ```v``` can be ```[x, y]```, ```[x, y, z]``` or ```z``` + : v + : [0, 0, v]) + [ [1, 0, 0, u.x], + [0, 1, 0, u.y], + [0, 0, 1, u.z], + [0, 0, 0, 1] ]; + +function rotate(a, v) = //! Generate a 4x4 rotation matrix, ```a``` can be a vector of three angles or a single angle around ```z```, or around axis ```v``` + is_undef(v) ? let(av = is_list(a) ? a : [0, 0, a], + cx = cos(av[0]), + cy = cos(av[1]), + cz = cos(av[2]), + sx = sin(av[0]), + sy = sin(av[1]), + sz = sin(av[2])) + [ + [ cy * cz, cz * sx * sy - cx * sz, cx * cz * sy + sx * sz, 0], + [ cy * sz, cx * cz + sx * sy * sz,-cz * sx + cx * sy * sz, 0], + [-sy, cy * sx, cx * cy, 0], + [ 0, 0, 0, 1] + ] + : let(s = sin(a), + c = cos(a), + C = 1 - c, + m = sqr(v.x) + sqr(v.y) + sqr(v.z), // m used instead of norm to avoid irrational roots as much as possible + u = v / sqrt(m)) + [ + [ C * v.x * v.x / m + c, C * v.x * v.y / m - u.z * s, C * v.x * v.z / m + u.y * s, 0], + [ C * v.y * v.x / m + u.z * s, C * v.y * v.y / m + c, C * v.y * v.z / m - u.x * s, 0], + [ C * v.z * v.x / m - u.y * s, C * v.z * v.y / m + u.x * s, C * v.z * v.z / m + c, 0], + [ 0, 0, 0, 1] + ]; + +function scale(v) = let(s = is_list(v) ? v : [v, v, v]) //! Generate a 4x4 matrix that scales by ```v```, which can be a vector of xyz factors or a scalar to scale all axes equally + [ + [s.x, 0, 0, 0], + [0, s.y, 0, 0], + [0, 0, s.z, 0], + [0, 0, 0, 1] + ]; + +function vec3(v) = [v.x, v.y, v.z]; //! Return a 3 vector with the first three elements of ```v``` +function transform(v, m) = vec3(m * [v.x, v.y, v.z, 1]); //! Apply 4x4 transform to a 3 vector by extending it and cropping it again +function transform_points(path, m) = [for(p = path) transform(p, m)]; //! Apply transform to a path +function unit(v) = let(n = norm(v)) n ? v / n : v; //! Convert ```v``` to a unit vector + +function transpose(m) = [ for(j = [0 : len(m[0]) - 1]) [ for(i = [0 : len(m) - 1]) m[i][j] ] ]; //! Transpose an arbitrary size matrix + +function identity(n, x = 1) = [for(i = [0 : n - 1]) [for(j = [0 : n - 1]) i == j ? x : 0] ]; //! Construct an arbitrary size identity matrix + +function reverse(v) = let(n = len(v) - 1) n < 0 ? [] : [for(i = [0 : n]) v[n - i]]; //! Reverse a vector diff --git a/utils/offset.scad b/utils/offset.scad new file mode 100644 index 0000000..452cf7b --- /dev/null +++ b/utils/offset.scad @@ -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 . +// + +//! 3D offset using `minkowski` with a `sphere`, so very slow if `$fn` is not kept small. The offset can be positive or negative. +//! +//! Can be used to round corners. Positive offsets will round convex corners, negative offsets round concave corners. To round both use [`round_3D()`](#round). +//! +//! If `chamfer_base` is true then the bottom edge is made suitable for 3D printing by chamfering when the angle gets shallower than 45 degrees. +include <../core.scad> + +module offset_3D(r, chamfer_base = false) { //! Offset 3D shape by specified radius ```r```, positive or negative. + module ball(r) + if(chamfer_base) + rotate_extrude() + intersection() { + rotate(180) + teardrop(0, r); + + translate([0, -r]) + square([r, 2 * r]); + } + else + sphere(r); + + if(r > 0) + minkowski() { + children(); + + ball(r); + } + else + if(r < 0) + render() difference() { + cube(inf / 2, center = true); + + minkowski() { + difference() { + cube(inf, center = true); + + children(); + } + ball(-r); + } + } + else + children(); +} diff --git a/utils/quadrant.scad b/utils/quadrant.scad new file mode 100644 index 0000000..7fe2da7 --- /dev/null +++ b/utils/quadrant.scad @@ -0,0 +1,40 @@ +// +// 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 . +// + +// +//! Square with one rounded corner. +// +include <../core.scad> + +module quadrant(w, r, center = false) { //! Draw a square with one rounded corner, can be centered on the arc centre, when ```center``` is ```true```. + offset = center ? r - w : 0; + translate([offset, offset]) + hull() { + intersection() { + translate([w - r, w - r]) + circle4n(r); + + square(w); + } + + square([w, eps]); + + square([eps, w]); + } +} diff --git a/utils/round.scad b/utils/round.scad new file mode 100644 index 0000000..bab60aa --- /dev/null +++ b/utils/round.scad @@ -0,0 +1,44 @@ +// +// 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 . +// + +//! Round 2D shapes uisng `offset()`, which is fast and 3D shapes with [`offset_3D()`](#offset), which is very slow. +//! +//! A single radius can be specified or separate internal and external radii. +//! If `chamfer_base` is `true` for `round_3D()` then the bottom edge is made suitable for 3D printing by chamfering once the +//! the angle gets shallower than 45 degrees. +include <../core.scad> +use + +module round(r, ir = undef, or = undef) { //! Round a 2D child, single radius or separate inside and outside radii + IR = is_undef(ir) ? r : ir; + OR = is_undef(or) ? r : or; + offset(OR) + offset(-OR -IR) + offset(IR) + children(); +} + +module round_3D(r, ir = undef, or = undef, chamfer_base = false) { //! Round a 3D child single radius or separate inside and outside radii + IR = is_undef(ir) ? r : ir; + OR = is_undef(or) ? r : or; + offset_3D(OR, chamfer_base) + offset_3D(-OR -IR, chamfer_base) + offset_3D(IR, chamfer_base) + children(); +} diff --git a/utils/rounded_cylinder.scad b/utils/rounded_cylinder.scad new file mode 100644 index 0000000..caccf55 --- /dev/null +++ b/utils/rounded_cylinder.scad @@ -0,0 +1,47 @@ +// +// 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 . +// + +// +//! Cylinder with a rounded end. +// +include <../core.scad> + +module rounded_corner(r, h, r2, ir = 0) { //! 2D version + assert(ir <= r - r2); + + translate([ir , 0]) + hull() { + square([eps, h]); + + square([r - ir, eps]); + + translate([r - r2 - ir, h - r2]) + intersection() { + circle4n(r2, $fs = 0.2); + + square(r2); + } + } +} + +module rounded_cylinder(r, h, r2, ir = 0, angle = 360) //! Rounded cylinder given radius ```r```, height ```h```, optional internal radius ```ir``` and optional ```angle``` +{ + rotate_extrude(angle = angle) + rounded_corner(r, h, r2, ir); +} diff --git a/utils/rounded_polygon.scad b/utils/rounded_polygon.scad new file mode 100644 index 0000000..11a7354 --- /dev/null +++ b/utils/rounded_polygon.scad @@ -0,0 +1,93 @@ +// +// 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 . +// + +// +//! Draw a polygon with rounded corners. Each element of the vector is the XY coordinate and a radius. Radius can be negative for a concave corner. +//! +//! Because the tangents need to be calculated to find the length these can be calculated separately and re-used when drawing to save calculating them twice. +// +include <../core.scad> + +function circle_tangent(p1, p2) = + let( + r1 = p1[2], + r2 = p2[2], + dx = p2.x - p1.x, + dy = p2.y - p1.y, + d = sqrt(dx * dx + dy * dy), + theta = atan2(dy, dx) + acos((r1 - r2) / d), + xa = p1.x +(cos(theta) * r1), + ya = p1.y +(sin(theta) * r1), + xb = p2.x +(cos(theta) * r2), + yb = p2.y +(sin(theta) * r2) + )[ [xa, ya], [xb, yb] ]; + +function rounded_polygon_tangents(points) = //! Compute the straight sections needed to draw and to compute the lengths + let(len = len(points)) + [for(i = [0 : len - 1]) + let(ends = circle_tangent(points[i], points[(i + 1) % len])) + for(end = [0, 1]) + ends[end]]; + +function sumv(v, i = 0, sum = 0) = i == len(v) ? sum : sumv(v, i + 1, sum + v[i]); + +// the cross product of 2D vectors is the area of the parallelogram between them. We use the sign of this to decide if the angle is bigger than 180. +function rounded_polygon_length(points, tangents) = //! Calculate the length given the point list and the list of tangents computed by ``` rounded_polygon_tangents``` + let( + len = len(points), + indices = [0 : len - 1], + straights = [for(i = indices) norm(tangents[2 * i] - tangents[2 * i + 1])], + arcs = [for(i = indices) let(p1 = tangents[2 * i + 1], + p2 = tangents[(2 * i + 2) % (2 * len)], + corner = points[(i + 1) % len], + c = [corner.x, corner.y], + v1 = p1 - c, + v2 = p2 - c, + r = abs(corner.z), + a = acos((v1 * v2) / sqr(r))) PI * (cross(v1,v2) <= 0 ? a : 360 - a) * r / 180] + ) + sumv(concat(straights, arcs)); + +module rounded_polygon(points, _tangents = undef) { //! Draw the rounded polygon from the point list, can pass the tangent list to save it being calculated + len = len(points); + indices = [0 : len - 1]; + tangents = _tangents ? _tangents : rounded_polygon_tangents(points); + + difference(convexity = points) { + union() { + for(i = indices) + if(points[i][2] > 0) + hull() { + translate([points[i].x, points[i].y]) + circle(points[i][2]); + polygon([tangents[(2 * i - 1 + 2 * len) % (2 * len)], tangents[2 * i], [points[i].x, points[i].y]]); + } + + polygon(tangents, convexity = points); + } + for(i = indices) + if(points[i][2] < 0) + hull() { + translate([points[i].x, points[i].y]) + circle(-points[i][2]); + + polygon([tangents[(2 * i - 1 + 2 * len) % (2 *len)], tangents[2 * i], [points[i].x, points[i].y]]); + } + } +} diff --git a/utils/sector.scad b/utils/sector.scad new file mode 100644 index 0000000..09fc237 --- /dev/null +++ b/utils/sector.scad @@ -0,0 +1,36 @@ +// +// 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 . +// + +// +//! A sector of a circle between two angles. +// +include <../core.scad> + +module sector(r, start_angle, end_angle) { //! Create specified sector given radius ```r```, ```start_angle``` and ```end_angle``` + R = r * sqrt(2) + 1; + + if(end_angle > start_angle) + intersection() { + circle4n(r); + + // A 4 triangle fan + polygon([[0, 0], + for(i = [0 : 4], a = start_angle + i * (end_angle - start_angle) / 4) R * [cos(a), sin(a)] ]); + } +} diff --git a/utils/sweep.scad b/utils/sweep.scad new file mode 100644 index 0000000..4c2672e --- /dev/null +++ b/utils/sweep.scad @@ -0,0 +1,160 @@ +// +// 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 . +// + +// +//! Utility to generate a polhedron by sweeping a 2D profile along a 3D path and utilities for generating paths. +//! +//! The initial orientation is the Y axis of the profile points towards the initial center of curvature, Frenet-Serret style. +//! This means the first three points must not be colinear. Subsequent rotations use the minimum rotation method. +//! +//! The path can be open or closed. If closed sweep ensures that the start and end have the same rotation to line up. +//! An additional twist around the path can be specified. If the path is closed this should be a multiple of 360. +// +include <../core.scad> + +use + +function transpose3(m) = [ [m[0].x, m[1].x, m[2].x], + [m[0].y, m[1].y, m[2].y], + [m[0].z, m[1].z, m[2].z] ]; +// +// Frenet-Serret frame +// +function fs_frame(tangents) = + let(tangent = tangents[0], + normal = tangents[1] - tangents[0], + binormal = cross(tangent, normal), + z = unit(tangent), + x = assert(norm(binormal) > 0.00001, "first three points are colinear") unit(binormal), + y = unit(cross(z, x)) + ) [[x.x, y.x, z.x], + [x.y, y.y, z.y], + [x.z, y.z, z.z]]; +// +// Computes the rotation with minimum angle that brings UNIT vectors a to b. +// The code fails if a and b are opposed to each other. +// +function rotate_from_to(a, b) = + let(axis = unit(cross(a, b))) + axis * axis >= 0.99 ? transpose3([b, axis, cross(axis, b)]) * [a, axis, cross(axis, a)] + : a * b > 0 ? [[ 1, 0, 0], [0, 1, 0], [0, 0, 1]] + : [[-1, 0, 0], [0, 1, 0], [0, 0, -1]]; +// +// Given two rotations A and B, calculates the angle between B*[1,0,0] +// and A*[1,0,0] that is, the total torsion angle difference between A and B. +// +function calculate_twist(A, B) = let(D = transpose3(B) * A) atan2(D[1][0], D[0][0]); +// +// Compute a 4x4 matrix to orientate a frame of the sweep given the position and a 3x3 rotation matrix. +// +function orientate(p, r) = + let(x = r[0], y = r[1], z = r[2]) + [[x.x, y.x, z.x], + [x.y, y.y, z.y], + [x.z, y.z, z.z], + [p.x, p.y, p.z]]; + +// +// Rotate around z +// +function rot3_z(a) = + let(c = cos(a), + s = sin(a)) + [ [ c, -s, 0], + [ s, c, 0], + [ 0, 0, 1] ]; + +// +// Calculate the unit tangent at a vertex given the indices before and after. One of these can be the same as i in the case +// of the start and end of a non closed path. +// +function tangent(path, before, i, after) = unit(unit(path[after] - path[i]) - unit(path[before] - path[i])); +// +// Generate all the surface points of the swept volume. +// +function skin_points(profile, path, loop, twist = 0) = + let(len = len(path), + last = len - 1, + + profile4 = [for(p = profile) [p.x, p.y, p.z, 1]], + + tangents = [tangent(path, loop ? last : 0, 0, 1), + for(i = [1 : last - 1]) tangent(path, i - 1, i, i + 1), + tangent(path, last - 1, last, loop ? 0 : last)], + + rotations = [for(i = 0, rot = fs_frame(tangents); + i < len; + i = i + 1, + rot = i < len ? rotate_from_to(tangents[i - 1], tangents[i]) * rot : undef) rot], + + missmatch = loop ? calculate_twist(rotations[0], rotations[last]) : 0, + rotation = missmatch + twist + ) + [for(i = [0 : last]) + let(za = rotation * i / last) + each profile4 * orientate(path[i], rotations[i] * rot3_z(za)) + ]; + +function cap(facets, segment = 0) = [for(i = [0 : facets - 1]) segment ? facets * segment + i : facets - 1 - i]; + +function quad(p, a,b,c,d) = norm(p[a] - p[c]) > norm(p[b] - p[d]) ? [[b, c, d], [b, d, a]] : [[a, b, c], [a, c, d]]; + +function skin_faces(points, segs, facets, loop) = [for(i = [0 : facets - 1], s = [0 : segs - (loop ? 1 : 2)]) + each quad(points, + s * facets + i, + s * facets + (i + 1) % facets, + ((s + 1) % segs) * facets + (i + 1) % facets, + ((s + 1) % segs) * facets + i)]; + +function sweep(path, profile, loop = false, twist = 0) = //! Generate the point list and face list of the swept volume + let( + segments = len(path), + facets = len(profile), + points = skin_points(profile, path, loop, twist), + skin_faces = skin_faces(points, segments, facets, loop), + faces = loop ? skin_faces : concat([cap(facets)], skin_faces, [cap(facets, segments - 1)]) + ) [points, faces]; + +module sweep(path, profile, loop = false, twist = 0) { //! Draw a polyhedron that is the swept volume + mesh = sweep(path, profile, loop, twist); + + polyhedron(points = mesh[0], faces = mesh[1]); +} + +function path_length(path, i = 0, length = 0) = //! Calculated the length along a path + i >= len(path) - 1 ? length + : path_length(path, i + 1, length + norm(path[i + 1] - path[i])); + +function circle_points(r = 1, z = 0) = //! Generate the points of a circle, setting z makes a single turn spiral + let(sides = r2sides(r)) + [for(i = [0 : sides - 1]) let(a = i * 360 / sides) [r * sin(a), r * cos(a), z * a / 360]]; + +function rectangle_points(w, h) = [[-w/2, -h/2, 0], [-w/2, h/2, 0], [w/2, h/2, 0], [w/2, -h/2, 0]]; //! Generate the points of a rectangle + +function arc_points(r, a = [90, 0, 180], al = 90) = //! Generate the points of a circular arc + let(sides = ceil(r2sides(r) * al / 360), tf = rotate(a)) + [for(i = [0 : sides]) let(t = i * al / sides) transform([r * sin(t), r * cos(t), 0], tf)]; + +function before(path1, path2) = //! Translate ```path1``` so its end meets the start of ```path2``` and then concatenate + let(end = len(path1) - 1, offset = path2[0] - path1[end]) + concat([for(i = [0 : end - 1]) path1[i] + offset], path2); + +function after(path1, path2) = //! Translate ```path2``` so its start meets the end of ```path1``` and then concatenate + let(end1 = len(path1) - 1, end2 = len(path2) - 1, offset = path1[end1] - path2[0]) + concat(path1, [for(i = [1 : end2]) path2[i] + offset]); diff --git a/utils/tube.scad b/utils/tube.scad new file mode 100644 index 0000000..fcb497c --- /dev/null +++ b/utils/tube.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +//! Simple tube or ring +// +include <../core.scad> + +module ring(or, ir) //! Create a ring with specified external and internal radii + difference() { + circle4n(or); + circle4n(ir); + } + +module tube(or, ir, h, center = true) //! Create a tube with specified external and internal radii and height ```h``` + linear_extrude(height = h, center = center, convexity = 5) + ring(or, ir); diff --git a/vitamins/ball_bearing.scad b/vitamins/ball_bearing.scad new file mode 100644 index 0000000..318a17b --- /dev/null +++ b/vitamins/ball_bearing.scad @@ -0,0 +1,68 @@ +// +// 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 . +// + +// +//! Simple model of ball bearings with seals, the colour of which can be specified. If silver they are assumed to be metal and the +//! part number gets a ZZ suffix. Any other colour is assumed to be rubber and the suffix is -2RS. +//! +//! If a ball bearing has a child it is placed on its top surface, the same as nuts and washers, etc. +//! +//! Also single bearing balls are modelled as just a silver sphere and a BOM entry. +// +include <../core.scad> + +function bb_name(type) = type[0]; //! Part code without shield type suffix +function bb_bore(type) = type[1]; //! Internal diameter +function bb_diameter(type) = type[2]; //! External diameter +function bb_width(type) = type[3]; //! Width +function bb_colour(type) = type[4]; //! Shield colour, "silver" for metal +function bb_rim(type) = bb_diameter(type) / 10; //! Inner and outer rim thickness + +module ball_bearing(type) { //! Draw a ball bearing + shield = bb_colour(type); + suffix = shield == "silver" ? "ZZ " : "-2RS "; + vitamin(str("ball_bearing(BB", bb_name(type), "): Ball bearing ", bb_name(type), suffix, bb_bore(type), "mm x ", bb_diameter(type), "mm x ", bb_width(type), "mm")); + rim = bb_rim(type); + h = bb_width(type); + od = bb_diameter(type); + id = bb_bore(type); + + module tube(od, id, h) + linear_extrude(height = h, center = true, convexity = 5) + difference() { + circle(d = od); + circle(d = id); + } + + color("silver") { + tube(od, od - rim, h); + tube(id + rim, id, h); + } + + color(shield) tube(od - rim, id + rim, h - 1); + + if($children) + translate_z(bb_width(type) / 2) + children(); +} + +module bearing_ball(dia) { //! Draw a steel bearing ball + vitamin(str(" bearing_ball(", dia, "): Steel ball ", dia, "mm")); + color("silver") sphere(d = dia); +} diff --git a/vitamins/ball_bearings.scad b/vitamins/ball_bearings.scad new file mode 100644 index 0000000..23fb42d --- /dev/null +++ b/vitamins/ball_bearings.scad @@ -0,0 +1,24 @@ +// +// 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 . +// +BB624 = ["624", 4, 13, 5, "blue"]; // 624 ball bearing for idlers +BB608 = ["608", 8, 22, 7, "OrangeRed"]; // 608 bearings for wades + +ball_bearings = [BB624, BB608]; + +use diff --git a/vitamins/batteries.scad b/vitamins/batteries.scad new file mode 100644 index 0000000..9429f42 --- /dev/null +++ b/vitamins/batteries.scad @@ -0,0 +1,50 @@ +// +// 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 . +// + +// +// w h t t t p n +// i e h a a o e +// d i i b b s g +// t g c +// h h k w h h d d h s +// t n 1 2 p +// e r +// s i +// s n +// g +bcontact = ["bcontact", 9.33, 9.75, 0.4, 2.86, 6, [1.6, 3, 5], [4.5, batt_spring]]; + +// l d n p p c L U c +// e i e o o o E S o +// n a g s s l D B n +// g m o t +// t e d d h u a +// t r c +// e t +// r +LUMINTOP = ["LUMINTOP", "Cell LUMINTOP 18650 LION with charger", 70.7, 18.4, 13, 5, 1, "white", [[3.32, 5], [3.32, -5]], 4, bcontact]; +S25R18650 = ["S25R18650", "Cell Samsung 25R 18650 LION", 65, 18.3, 13, 10, 0, "MediumSeaGreen", [], 0, bcontact]; +AACELL = ["AACELL", "Cell AA", 50.5, 14.5, 11, 5.5, 1, "grey", [], 0, bcontact]; +AAACELL = ["AAACELL", "Cell AAA", 44.5, 10.5, 8, 3.8, 0.8, "grey", [], 0, bcontact]; +CCELL = ["CCELL", "Cell C", 50, 26.2, 20, 7.5, 1.5, "brown", [], 0, bcontact]; +DCELL = ["DCELL", "Cell D", 61.5, 34.2, 22, 8.2, 2.4, "brown", [], 0, bcontact]; + +batteries = [AAACELL, AACELL, CCELL, DCELL, LUMINTOP, S25R18650]; + +use diff --git a/vitamins/battery.scad b/vitamins/battery.scad new file mode 100644 index 0000000..7fe609e --- /dev/null +++ b/vitamins/battery.scad @@ -0,0 +1,161 @@ +// +// 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 . +// + +// +//! Actually just single cells at the moment, shown here with mating contacts in place. +//! +//! Note that the [Lumintop LM34](http://www.lumintop.com/lm34c-usb-rechargeable-18650-li-ion-battery.html) has a built in charger with a USB socket and two LEDs. +//! +//! The battery length includes its contacts and the origin is the centre of that length. As well as drawing the battery and contacts there are functions +//! exposing enough information to make a battery box. +// +include <../core.scad> +use +use <../utils/rounded_cylinder.scad> + +function battery_length(type) = type[2]; //! Total length including terminals +function battery_diameter(type) = type[3]; //! Casing diameter +function battery_neg_dia(type) = type[4]; //! Negative terminal diameter +function battery_pos_dia(type) = type[5]; //! Positive terminal diameter +function battery_pos_height(type) = type[6]; //! Positive terminal height above the casing +function battery_colour(type) = type[7]; //! Casing colour +function battery_led_positions(type) = type[8]; //! LED positions for Lumintop +function battery_usb_offset(type) = type[9]; //! USB connector offset from the top +function battery_contact(type) = type[10]; //! Contact type + +module battery_led_positions(type) { //! Position of the LEDs on a Lumintop + posns = battery_led_positions(type); + for($i = [0 : 1 : len(posns) - 1]) + translate([posns[$i].x, posns[$i].y, battery_length(type) / 2 - battery_pos_height(type)]) + children(); +} + +module battery(type) { //! Draw a battery + vitamin(str("battery(", type[0], "): ", type[1])); + len = battery_length(type); + + l = 6; + iw1 = 7; + iw2 = 5.7; + ih1 = 1; + ih2 = 1.85; + h = 2.65; + t = 0.4; + + module D() { + hull() { + translate([-iw1 / 2, h - t - ih1]) + square([iw1, ih1]); + + translate([-iw2 / 2, h - t - ih2]) + square([iw2, ih2]); + } + } + + color(battery_colour(type)) render() difference() { + translate_z(-battery_pos_height(type) / 2) + cylinder(d = battery_diameter(type), h = len - battery_pos_height(type), center = true); + + if(battery_usb_offset(type)) + translate([battery_diameter(type) / 2, 0, len / 2 - battery_usb_offset(type) + h / 2]) + rotate([-90, 0, 90]) + linear_extrude(height = l + 1) + offset(delta = t) + D(); + } + color("gold") + translate_z(len / 2 - battery_pos_height(type)) + rounded_cylinder(r = battery_pos_dia(type) / 2, h = battery_pos_height(type) + eps, r2 = 0.5); + + color("silver") { + if(battery_usb_offset(type)) + translate([battery_diameter(type) / 2 - 1, 0, len / 2 - battery_usb_offset(type) + h / 2]) + rotate([-90, 0, 90]) { + linear_extrude(height = l) + difference() { + offset(t) D(); + D(); + } + + translate_z(l - 1) + linear_extrude(height = 1) + D(); + } + + translate_z(-len / 2) + vflip() + cylinder(d = battery_neg_dia(type), h = eps); + + } + + battery_led_positions(type) + color(["red","green","blue"][$i]) + cylinder(d = 1.5, h = eps); +} + +function contact_width(type) = type[1]; //! Width of the flat part +function contact_height(type) = type[2]; //! Height of the flat part +function contact_thickness(type) = type[3]; //! Thickness of the metal +function contact_tab_width(type) = type[4]; //! Width of the tab +function contact_tab_length(type) = type[5]; //! Length of the tab +function contact_pos(type) = type[6]; //! Positive contact dimple height and top and bottom internal diameter +function contact_neg(type) = type[7]; //! Negative spring height above the plate when compressed and the spring type + +module battery_contact(type, pos = true) { //! Draw a positive or negative battery contact for specified battery + vitamin(str("battery_contact(", type[0], ", ", pos, "): Battery ", pos ? "positive" : "negative", " contact")); + + neg = 9; + + tw = contact_tab_width(type); + h = contact_height(type); + hole_y = -contact_tab_length(type) + tw / 2; + t = contact_thickness(type); + + color("silver") { + rounded_rectangle([contact_width(type), h, t], r = 1, center = false); + + translate([0, -h / 2, t]) + rotate([90, 0, 0]) + linear_extrude(height = t) + difference() { + hull() { + translate([-tw / 2, -1]) + square([tw, 1]); + + translate([0, hole_y]) + circle(d = tw); + } + translate([0, hole_y]) + circle(tw / 4); + } + + if(pos) { + p = contact_pos(type); + + cylinder(d1 = p.z + 2 * t, d2 = p.y + 2 * t, h = p.x); + } + else { + p = contact_neg(type); + + not_on_bom() + translate_z(t) + comp_spring(p.y, p.x - t); + } + } +} diff --git a/vitamins/belt.scad b/vitamins/belt.scad new file mode 100644 index 0000000..37ad1d5 --- /dev/null +++ b/vitamins/belt.scad @@ -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 . +// + +// +//! Models timing belt running over toothed or smooth pulleys and calculates an accurate length. +//! Only models 2D paths, so not core XY! +//! +//! By default the path is a closed loop but a gap length and position can be specified to make open loops. +//! +//! Individual teeth are not drawn, instead they are represented by a lighter colour. +// +include <../core.scad> +use <../utils/rounded_polygon.scad> + +function belt_pitch(type) = type[1]; //! Pitch in mm +function belt_width(type) = type[2]; //! Width in mm +function belt_thickness(type) = type[3]; //! Total thickness including teeth +function belt_tooth_height(type) = type[4]; //! Tooth height +function belt_pitch_height(type) = belt_tooth_height(type) + type[4]; //! Offset of the pitch radius from the tips of the teeth + +function no_point(str) = chr([for(c = str) if(c == ".") ord("p") else ord(c)]); +// +// We model the belt path at the pitch radius of the pulleys and the pitch line of the belt to get an accurate length. +// The belt is then drawn by offseting each side from the pitch line. +// +module belt(type, points, gap = 0, gap_pt = undef) { //! Draw a belt path given a set of points and pitch radii where the pulleys are. Closed loop unless a gap is specified + belt_colour = grey20; + tooth_colour = grey50; + width = belt_width(type); + pitch = belt_pitch(type); + thickness = belt_thickness(type); + part = str(type[0],pitch); + vitamin(str("belt(", no_point(part), "x", width, ", ", points, arg(gap, 0), arg(gap_pt, undef), "): Belt ", part," x ", width, "mm x ", length, "mm")); + + len = len(points); + + tangents = rounded_polygon_tangents(points); + + length = ceil((rounded_polygon_length(points, tangents) - gap) / pitch) * pitch; + + module shape() rounded_polygon(points, tangents); + + module gap() + if(gap) + translate(gap_pt) + square([gap, thickness + eps], center = true); + + color(belt_colour) + linear_extrude(height = width, center = true) + difference() { + offset(thickness - belt_pitch_height(type)) shape(); + offset(-belt_pitch_height(type) + belt_tooth_height(type)) shape(); + gap(); + + } + color(tooth_colour) + linear_extrude(height = width, center = true) + difference() { + offset(-belt_pitch_height(type) + belt_tooth_height(type)) shape(); + offset(-belt_pitch_height(type)) shape(); + gap(); + } +} + +function belt_length(points, gap = 0) = rounded_polygon_length(points, rounded_polygon_tangents(points)) - gap; //! Compute belt length given path and optional gap diff --git a/vitamins/belts.scad b/vitamins/belts.scad new file mode 100644 index 0000000..904621f --- /dev/null +++ b/vitamins/belts.scad @@ -0,0 +1,35 @@ +// +// 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 . +// + +// +// Belt model +// +// p w t t p +// i i h o i +// t d i o t +// c t c t c +// h h k h h line from tooth base +// +T5x6 = ["T", 5, 6, 2.2, 1.2, 0.5]; +T5x10 = ["T", 5, 10, 2.2, 1.2, 0.5]; +T2p5x6 =["T", 2.5, 6, 1.7, 0.7, 0.3]; +GT2x6 = ["GT", 2.0, 6, 1.38, 0.75, 0.254]; + +belts = [T5x6, T5x10, T2p5x6, GT2x6]; +use diff --git a/vitamins/blower.scad b/vitamins/blower.scad new file mode 100644 index 0000000..f2ea839 --- /dev/null +++ b/vitamins/blower.scad @@ -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 . +// + +// +//! Models of radial blowers. +// +include <../core.scad> +use <../utils/rounded_cylinder.scad> + +function blower_length(type) = type[2]; //! Length of enclosing rectangle +function blower_width(type) = type[3]; //! Width of enclosing rectangle +function blower_depth(type) = type[4]; //! Height +function blower_bore(type) = type[5]; //! The air intake hole diameter +function blower_screw(type) = type[6]; //! The type of screws needed +function blower_hub(type) = type[7]; //! Rotor hub diameter +function blower_axis(type) = type[8]; //! XY coordinates of the axle +function blower_screw_hole(type) = type[9]; //! Screw hole diameter +function blower_screw_holes(type) = type[10]; //! List of XY coordinates of the screw holes +function blower_exit(type) = type[11]; //! The width of the exit port +function blower_hub_height(type) = type[12]; //! Height of the rotor +function blower_base(type) = type[13]; //! Thickness of the base +function blower_top(type) = type[14]; //! Thickness of the top +function blower_wall(type) = type[15]; //! Side wall thickness +function blower_lug(type) = type[16]; //! Height of the lugs + +fan_colour = grey20; + +module blower(type) { //! Draw specified blower + length = blower_length(type); + width = blower_width(type); + depth = blower_depth(type); + screw = blower_screw(type); + + r1 = blower_axis(type)[0]; + r2 = width - blower_axis(type)[1]; + r3 = length - blower_axis(type)[0]; + function radius(a) = a < 90 ? r1 * exp(a * ln(r2 / r1) / 90) + : r2 * exp((a - 90) * ln(r3 / r2) / 90); + function spiral(a) = let(r = radius(a)) [-r * cos(a), r * sin(a)]; + + module shape(inside = false) + union() { + hull() { + translate(blower_axis(type)) + polygon([for(a = [0 : 1 : 360]) spiral(a)]); + + if(blower_exit(type) > length / 2) + square([blower_exit(type), 1]); + } + offset = inside ? 5 : 0; + translate([0, -offset]) + square([blower_exit(type), blower_axis(type)[1] + offset]); + } + + vitamin(str("blower(", type[0], "): ", type[1])); + + color(fan_colour) { + // screw lugs + linear_extrude(height = blower_lug(type), center = false) + for(hole = blower_screw_holes(type)) + difference() { + hull() { + translate(hole) + circle(d = blower_screw_hole(type) + 2 * blower_wall(type)); + + translate(blower_axis(type)) + circle(d = blower_screw_hole(type) + 2 * blower_wall(type) + 7); + } + circle(d = blower_screw_hole(type)); + + shape(true); + } + // rotor + translate(concat(blower_axis(type), [blower_base(type) + 1])) + rounded_cylinder(r = blower_hub(type) / 2, h = blower_hub_height(type) - blower_base(type) - 1, r2 = 1); + + *%square([length, width]); + + // base + linear_extrude(height = blower_base(type)) + difference() { + shape(); + + translate(concat(blower_axis(type), [blower_base(type)])) + circle(d = 2); + } + // sides + linear_extrude(height = depth) + difference() { + shape(); + + offset(-blower_wall(type)) + shape(true); + } + + // top + translate_z(depth -blower_top(type)) + linear_extrude(height = blower_top(type)) + difference() { + shape(); + + translate(concat(blower_axis(type), [blower_base(type)])) + circle(d = blower_bore(type)); + } + } +} + +module blower_hole_positions(type) //! Translate children to screw hole positions + for(hole = blower_screw_holes(type)) + translate(hole) + children(); diff --git a/vitamins/blowers.scad b/vitamins/blowers.scad new file mode 100644 index 0000000..3e1b2f4 --- /dev/null +++ b/vitamins/blowers.scad @@ -0,0 +1,25 @@ +// +// 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 . +// + +RB5015 = ["RM5015", "Blower Runda RB5015", 51.3, 51, 15, 31.5, M4_cap_screw, 26, [27.3, 25.4], 4.5, [[4.3, 45.4], [47.3,7.4]], 20, 14, 1.5, 1.3, 1.2, 15]; +PE4020 = ["PE4020", "Blower Pengda Technology 4020", 40, 40, 20, 27.5, M3_cap_screw, 22, [21.5, 20 ], 3.2, [[37,3],[3,37],[37,37]], 29.3, 17, 1.7, 1.2, 1.3, 13]; + +blowers = [PE4020, RB5015]; + +use diff --git a/vitamins/bulldog.scad b/vitamins/bulldog.scad new file mode 100644 index 0000000..874e0b2 --- /dev/null +++ b/vitamins/bulldog.scad @@ -0,0 +1,83 @@ +// +// 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 . +// + +// +//! Crude representation of a bulldog clip. The handle is not currently drawn but its length can be +//! accessed to allow clearance. Used for holding glass on 3D printer beds but Swiss picture clips can be +//! better. +// +include <../core.scad> +use <../utils/rounded_polygon.scad> +use <../utils/sector.scad> + +function bulldog_length(type) = type[1]; //! Length along the profile +function bulldog_depth(type) = type[2]; //! Depth from the back to the front of the tubes +function bulldog_height(type) = type[3]; //! Height at the back +function bulldog_thickness(type) = type[4]; //! Thickness of the metal +function bulldog_tube(type) = type[5] / 2; //! Outside diameter of the tubes +function bulldog_radius(type) = type[6]; //! Outside radius of the back corners +function bulldog_handle_length(type) = type[7]; //! Length that the handle protrudes from the back + +module bulldog_shape(depth, height, radius, tube, open) { + rounded_polygon([ + [-depth / 2 + radius, -height / 2 + radius, radius], + [-depth / 2 + radius, height / 2 - radius, radius], + [ depth / 2 - tube, open / 2 + tube, -tube], + [ depth / 2 + tube, height / 2, tube], + [ depth / 2 + tube, -height / 2, tube], + [ depth / 2 - tube, -open / 2 - tube, -tube], + + ]); +} + +module bulldog(type, open = 4) { //! Draw bulldog clip open by specified amount + tube = bulldog_tube(type); + thickness = bulldog_thickness(type); + depth = bulldog_depth(type); + length = bulldog_length(type); + height = bulldog_height(type); + rad = bulldog_radius(type); + gap = open + thickness * 2; + + vitamin(str("bulldog(", type[0], "): Bulldog clip ",length, "mm")); + + color("yellow") + translate([depth / 2 - thickness - eps, 0]) + rotate([90, 0, 0]) + linear_extrude(length, center = true) + union() { + difference() { + bulldog_shape(depth, height, rad, tube, gap); + + offset(-thickness) + bulldog_shape(depth, height, rad, tube, gap); + + translate([depth / 2 - tube, -height]) + square([depth, 2 * height]); + } + + for(side = [-1, 1]) + translate([depth / 2 - tube, side * (open / 2 + tube)]) + difference() { + mirror([0, side < 0 ? 1 : 0]) + sector(tube, -90, 210); + circle(tube - thickness); + } + } +} diff --git a/vitamins/bulldogs.scad b/vitamins/bulldogs.scad new file mode 100644 index 0000000..23bfb5a --- /dev/null +++ b/vitamins/bulldogs.scad @@ -0,0 +1,35 @@ +// +// 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 . +// + +// +// Crude representation of a bulldog clip +// +// l d h t t r h +// e e e h u a a +// n p i i b d n +// g t g c e i d +// t h h k u l +// h s e +// +small_bulldog = ["small_bulldog", 19, 12, 8, 0.25, 2.67, 1, 16]; +large_bulldog = ["large_bulldog", 25, 15,12, 0.28, 3.00, 2.4, 20]; + +bulldogs = [small_bulldog, large_bulldog]; + +use diff --git a/vitamins/button.scad b/vitamins/button.scad new file mode 100644 index 0000000..aaa3f94 --- /dev/null +++ b/vitamins/button.scad @@ -0,0 +1,74 @@ +// +// 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 . +// + +// +//! PCB mounted buttons. Can optionally have a coloured cap +// +include <../core.scad> +use <../utils/rounded_cylinder.scad> + +function square_button_width(type) = type[1]; //! Width and depth of the base +function square_button_height(type) = type[2]; //! Height of the base +function square_button_wall(type) = type[3]; //! Offset of the metal part +function square_button_rivit(type) = type[4]; //! Size of the corner rivets +function square_button_d(type) = type[5]; //! Button diameter +function square_button_h(type) = type[6]; //! Height of the button above the PCB +function square_button_cap_flange_d(type) = type[7]; //! Diameter of the flange of the cap +function square_button_cap_d(type) = type[8]; //! Diameter of the body of the cap +function square_button_cap_h(type) = type[9]; //! Height of the cap including the stem +function square_button_cap_stem(type) = type[10]; //! Length of the cap stem +function square_button_cap_flange_h(type) = type[11]; //! Height of the cap flange + +module square_button(type, colour = "yellow") { //! Draw square button with specified cap colour if it has a cap + w = square_button_width(type); + flange_d = square_button_cap_flange_d(type); + vitamin(str("square_button(", type[0], flange_d ? str(", \"", colour, "\"") : "", "): Square button ", w, "mm", + flange_d ? str(" with ", colour, " cap") : "")); + h = square_button_height(type); + wall = square_button_wall(type); + rivit = square_button_rivit(type); + pitch = (w/ 2 - wall - rivit * 0.75); + stem = square_button_cap_stem(type); + + color(grey20) { + rounded_rectangle([w, w, h - 0.5], r = wall, center = false); + + for(x = [-1, 1], y = [-1, 1]) + translate([x * pitch, y * pitch]) + cylinder(d = rivit, h = h); + + cylinder(d = square_button_d(type), h = square_button_h(type)); + } + + color("silver") + translate_z(h - 0.5) + rounded_rectangle([w - 2 * wall, w - 2 * wall, 0.2], r = wall, center = true); + + if(flange_d) + translate_z(square_button_h(type)) + color(colour) rotate_extrude() { + square([square_button_d(type) / 2, stem]); + + translate([0, stem]) { + square([flange_d / 2, square_button_cap_flange_h(type)]); + + rounded_corner(r = square_button_cap_d(type) / 2, h = square_button_cap_h(type) - stem, r2 = 0.5); + } + } +} diff --git a/vitamins/buttons.scad b/vitamins/buttons.scad new file mode 100644 index 0000000..e4f64ac --- /dev/null +++ b/vitamins/buttons.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +// w h w r b b c c c c c +// i e a i u u a a a a a +// d i l v t t p p p p p +// t g l i +// h h t d h f d h s f +// d t h +button_12mm = ["button_12mm", 12, 4.0, 0.8, 1.5, 6.8, 4.3, 12.86, 11.44, 8.15, 2.7, 1.4]; +button_6mm = ["button_6mm", 6, 4.0, 0.2, 1.0, 3.5, 5.0, 0]; +button_4p5mm= ["button_4p5mm", 4.5, 3.1, 0.1, 0.9, 2.4, 4.5, 0]; + +buttons = [button_4p5mm, button_6mm, button_12mm]; + +use diff --git a/vitamins/cable_strip.scad b/vitamins/cable_strip.scad new file mode 100644 index 0000000..92bbd13 --- /dev/null +++ b/vitamins/cable_strip.scad @@ -0,0 +1,159 @@ +// +// 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 . +// + +// +//! A strip of polypropylene used with ribbon cable to make a cable flexible in one direction only. +//! +//! Modelled with a Bezier spline, which is not quite the same as a miniumum energy curve but very close, epecially +//! near the extreme positions, where the model needs to be accurate. +//! +//! When the sides are constrained then a circular model is more accurate. +// +include <../core.scad> +cable_strip_thickness = 0.8; +function ribbon_clamp_slot(ways) = ways * inch(0.05) + 1; +function ribbon_clamp_slot_depth() = cable_strip_thickness + inch(0.05); +function cable_strip_thickness() = cable_strip_thickness; + +use <../utils/bezier.scad> +use <../utils/sweep.scad> + +cable_strip_color = "green"; + +function cable_strip_control_points(depth, min_z, pos) = let(z = min(min_z, min_z + pos)) +[ + [0, 0, 0], [0, 0, z], [0, depth, z], [0, depth, pos] +]; + +function bezier_cable_length(depth, min_z, pos) = //! Calculate a length that will achieve the desired minimum z + bezier_length(adjust_bezier_z(cable_strip_control_points(depth, min_z, pos), min_z)); + +module bezier_cable_strip(ways, depth, length, travel, pos, below, extra) { //! Draw a cable strip using a Bezier curve + width = ceil(ribbon_clamp_slot(ways) - 1); + + thickness = cable_strip_thickness; + + total = 2 * extra + length; + + vitamin(str("bezier_cable_strip(", ways, ", ", depth, ", ", length, ", ", travel, ", ", pos, ", ", below, ", ", extra, + "): Polypropylene strip ", total, "mm x ", width, "mm x ", thickness, "mm")); + + c = cable_strip_control_points(depth, -below + extra, pos); + v = adjust_bezier_length(c, length); + + steps = 100; + extra_v = [0, 0, extra]; + + path = [v[0] + extra_v, each bezier_path(v, steps), v[3] + extra_v]; + + color(cable_strip_color) + translate_z(-extra) + sweep(path, rectangle_points(width, thickness)); + *echo(cable_strip_lengh = length); + *translate_z(-extra) sweep(v, circle_points(1)); +} + +function cable_strip_length(depth, travel, extra = 15) = ceil(travel / 2 + 2 * extra + PI * depth); //! Calculate circular cable strip length + +module cable_strip(ways, depth, travel, x, extra = 15) { //! Draw a cable stripe with a semi circular fold + + width = ribbon_clamp_slot(ways); + + thickness = cable_strip_thickness; + + radius = depth / 2; + + top = travel / 4 + extra + x / 2; + bottom = travel / 4 + extra - x /2; + + length = max(top, bottom); + + total = ceil(top + bottom + PI * depth); + w = floor(width - 2); + + vitamin(str("cable_strip(", ways, ", ", depth, ", ", travel, ", ", x, arg(extra, 15), "): Polypropylene strip ", total, "mm x ", w, "mm x ", thickness, "mm")); + + color(cable_strip_color) linear_extrude(height = w, center = true, convexity = 4) + difference() { + union() { + translate([-bottom, radius]) + circle(radius); + + translate([-bottom, 0]) + square([length, depth]); + } + union() { + translate([-bottom, radius]) + circle(radius - thickness); + + translate([-bottom, thickness]) + square([length + 1, depth - thickness * 2]); + } + translate([0, -thickness / 2]) + square([travel, thickness * 2]); + + translate([x, depth - thickness - thickness / 2]) + square([travel, thickness * 2]); + } +} + +function elliptical_cable_strip_length(p1, pmax, extra = 15) = ceil(PI * pow((pow(abs((pmax - p1)[0] / 2),1.5) + pow(75,1.5))/2, 1/1.5)) + 2 * extra; + +module elliptical_cable_strip(ways, p1, p2, pmax, extra = 15) { + width = ribbon_clamp_slot(ways); + + thickness = cable_strip_thickness; + w = floor(width - 1); + + max_delta = pmax - p1; + delta = p2 - p1; + + A = abs(max_delta[0] / 2); + B = 75; + + length = ceil(PI * pow((pow(A,1.5) + pow(B,1.5))/2, 1/1.5)); + total = length + 2 * extra; + + vitamin(str("elliptical_cable_strip(", ways, ", ", p1, ", ", p2, ", ", pmax, arg(extra, 15), + "): Polypropylene strip ", total, "mm x ", w, "mm x ", thickness, "mm")); + + a = abs(delta[0] / 2); + b = pow(2 * pow(length / PI, 1.5) - pow(a, 1.5), 1/1.5); + + translate(p1 - [a, 0, 0]) + multmatrix(m = [ [1, 0, 0, 0], + [delta[1] / delta[0], 1, 0, delta[1] / 2], + [delta[2] / delta[0], 0, 1, delta[2] / 2], + [0, 0, 0, 1] ]) + + color(cable_strip_color) linear_extrude(height = w, center = true, convexity = 4) + difference() { + union() { + square([(a + thickness) * 2, extra * 2], center = true); + translate([0, -extra]) + ellipse((a + thickness), b + thickness); + } + translate([0, (b + 1) / 2]) + square([a * 2 + 1, b + 1], center = true); + + square([a * 2, extra * 2], center = true); + translate([0, -extra]) + ellipse(a, b); + } +} diff --git a/vitamins/component.scad b/vitamins/component.scad new file mode 100644 index 0000000..346b1a9 --- /dev/null +++ b/vitamins/component.scad @@ -0,0 +1,450 @@ +// +// 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 . +// + +// +//! Various electronic components used in hot ends and heated beds. +// + +// +// Resistor model for hot end +// +include <../core.scad> +include +include +include +use <../utils/rounded_cylinder.scad> + +function resistor_length(type) = type[2]; //! Body length +function resistor_diameter(type) = type[3]; //! Body diameter +function resistor_wire_diameter(type) = type[4]; //! Wire diameter +function resistor_wire_length(type) = type[5]; //! Wire length from body +function resistor_hole(type) = type[6]; //! Hole big enough to glue it into +function resistor_colour(type) = type[7]; //! Body colour +function resistor_radial(type) = type[8]; //! Radial gives bead thermistor style body +function resistor_sleeved(type) = type[9]; //! Are the leads sleeved + +splay_angle = 2; // radial lead splay angle + +module resistor(type) { //! Draw specified type of resitor + length = resistor_length(type); + dia = resistor_diameter(type); + + vitamin(str("resistor(", type[0], "): ", type[1])); + // + // wires + // + color([0.7, 0.7, 0.7]) + if(resistor_radial(type)) + for(side= [-1,1]) + translate([side * dia / 6, 0, length / 2]) + rotate([0, splay_angle * side, 0]) + cylinder(r = resistor_wire_diameter(type) / 2, h = resistor_wire_length(type), center = false); + else + cylinder(r = resistor_wire_diameter(type) / 2, h = length + 2 * resistor_wire_length(type), center = true); + // + // Sleeving + // + if(resistor_sleeved(type)) + color([0.5, 0.5, 1]) + if(resistor_radial(type)) + for(side= [-1, 1]) + translate([side * resistor_diameter(type) / 6, 0, length / 2]) { + rotate([0, splay_angle * side, 0]) + cylinder(r = resistor_wire_diameter(type) / 2 + 0.1, h = resistor_wire_length(type) - 5, center = false); } + // + // Body + // + color(resistor_colour(type)) + if(resistor_radial(type)) + hull() { + translate_z(-length / 2 + dia / 2) + sphere(d = dia); + + cylinder(d = dia / 2, h = length / 2); + } + else + rotate_extrude() + for(y = [0, 1]) + mirror([0, y]) + rounded_corner(r = dia / 2, h = length / 2, r2 = dia / 10); +} + +module sleeved_resistor(type, sleeving, bare = 5, heatshrink = false) { //! Draw a resistor with sleeved leads and option heatshrink + resistor(type); + sleeving_length = resistor_wire_length(type) - bare; + + for(side= [-1,1]) + if(resistor_radial(type)) { + translate([side * resistor_diameter(type) / 6, 0, 0]) + rotate([0, splay_angle * side, 0]) { + if(!resistor_sleeved(type)) + translate_z(sleeving_length / 2 + resistor_length(type) / 2 + 20 * exploded()) + tubing(sleeving, sleeving_length); + + if(heatshrink) + translate_z(sleeving_length + resistor_length(type) / 2 + bare / 2 + 30 * exploded()) + tubing(heatshrink); + } + } + else { + translate_z(side * (resistor_length(type) + sleeving_length + 40 * exploded()) / 2) + tubing(sleeving, sleeving_length); + + if(heatshrink) + translate_z(side * (resistor_length(type) /2 + sleeving_length + 30 * exploded())) + tubing(heatshrink); + } +} + +function al_clad_length(type) = type[1]; //! Body length +function al_clad_width(type) = type[2]; //! Width including tabs +function al_clad_tab(type) = type[3]; //! Tab width +function al_clad_hpitch(type) = type[4]; //! Lengthways pitch between screw holes +function al_clad_vpitch(type) = type[5]; //! Widthways pitch between screw holes +function al_clad_thickness(type) = type[6]; //! Tab thickness +function al_clad_hole(type) = type[7]; //! Hole diameter +function al_clad_clearance(type) = type[8]; //! Clearance from screw hole centre to the body +function al_clad_height(type) = type[9]; //! Body height +function al_clad_wire_length(type) = type[10]; //! Total length including wires + +module al_clad_resistor_hole_positions(type) //! Position children at the screw holes of an aluminium clad resistor + for(end = [-1, 1]) + translate([end * al_clad_hpitch(type) / 2, end * al_clad_vpitch(type) / 2, al_clad_thickness(type)]) + children(); + +module al_clad_resistor_holes(type, h = 100) //! Drill screw holes for an aluminium clad resistor + al_clad_resistor_hole_positions(type) + drill(screw_clearance_radius(al_clad_hole(type) > 3 ? M3_pan_screw : M2p5_pan_screw), h); + +module al_clad_resistor(type, value, leads = true) { //! Draw an aluminium clad resistor + vitamin(str("al_clad_resistor(", type[0], ", ", value, arg(leads, true, "leads"), + "): Resistor aluminium clad ", type[0], " ", value)); + length = al_clad_length(type); + width = al_clad_width(type); + height = al_clad_height(type); + tab = al_clad_tab(type); + thickness = al_clad_thickness(type); + terminal_h = 4; + terminal_t = 1; + terminal_l = 5; + + body = al_clad_vpitch(type) - 2 * al_clad_clearance(type); + + color("silver") { + rotate([90, 0, 90]) + linear_extrude(height = length, center = true) + hull() { + translate([0, al_clad_height(type) / 2]) + intersection() { + square([body, al_clad_height(type)], center = true); + + circle(body / 2 - eps); + } + translate([0, thickness / 2]) + square([body, thickness], center = true); + } + linear_extrude(height = thickness) + difference() { + for(end = [-1, 1]) + translate([end * (length - tab) / 2, end * (width - width / 2) / 2]) + square([tab, width / 2], center = true); + + al_clad_resistor_hole_positions(type) + circle(d = al_clad_hole(type)); + + } + if(leads) { + translate_z(height / 2) + rotate([0, 90, 0]) + cylinder(r = 1, h = al_clad_wire_length(type) - 2 * terminal_l + eps, center = true); + + for(end = [-1, 1]) + translate([end * (al_clad_wire_length(type) - terminal_l) / 2, 0, height / 2]) + rotate([90, 0, 0]) + linear_extrude(height = terminal_t, center = true) difference() { + square([terminal_l, terminal_h], center = true); + + circle(r = 1); + } + } + } + color("black") + translate_z(height / 2) + rotate([0, 90, 0]) + cylinder(r = leads ? 3 : height / 2 - 2, h = length + eps, center = true); +} + +module al_clad_resistor_assembly(type, value, sleeved = true) { //* Draw aluminium clad resistor with optional sleaving, positions children at the screw positions + sleeving_length = 15; + sleeving = HSHRNK32; + + al_clad_resistor(type, value); + + if(sleeved) + for(end = [-1, 1]) + translate([end * (al_clad_length(type) + sleeving_length + 0) / 2, 0, al_clad_height(type) / 2]) + rotate([0, 90, 0]) + scale([1.5, 0.66, 1]) + tubing(sleeving, sleeving_length); + + al_clad_resistor_hole_positions(type) + children(); +} + +function TO220_thickness() = 1.5; //! Thickness of the tab of a TO220 + +module TO220(description, leads = 3, lead_length = 16) { //! Draw a TO220 package, use ```description``` to describe what it is + width = 10.2; + inset = 1.5; + hole = 3.3; + length = 15; + height = 4.4; + lead_height = 1.9; + lead_t = 0.4; + lead_w = 0.7; + lead_w2 = 1.4; + lead_l = 4.2; + body = 8; + hole_y = 2.9; + + vitamin(str("TO220(\"", description, "\"", arg(leads, 3, "leads"), arg(lead_length, 16, "lead_length"), "): ", description)); + + translate([0, -length + hole_y]) { + color("silver") { + linear_extrude(height = TO220_thickness()) + difference() { + translate([-width / 2, inset]) + square([width, length - inset]); + + translate([0, length - hole_y]) + circle(d = hole); + + for(side = [-1, 1]) + translate([side * width / 2, 0]) + square([inset * 2, body * 2], center = true); + } + + for(i = [-1 : 1]) + if(i || leads == 3) { + translate([inch(0.1) * i, -lead_length / 2, lead_height]) + cube([lead_w, lead_length, lead_t], center = true); + + translate([inch(0.1) * i, -lead_l / 2, lead_height]) + cube([lead_w2, lead_l, lead_t], center = true); + } + } + color("dimgrey") + translate([-width / 2, 0, eps]) + cube([width, body, height]); + } + translate_z(TO220_thickness()) + children(); +} + +panel_USBA_pitch = 30; + +module panel_USBA_hole_positions() //! Place children at hole positions + for(side = [-1, 1]) + translate([side * panel_USBA_pitch / 2, 0]) + children(); + +module panel_USBA_holes(h = 100) { //! Make holes for USBA connector + corner_clearance = 2 * cnc_bit_r * (1 - 1 / sqrt(2)); + width = 5.5 + corner_clearance; + length = 13 + corner_clearance; + + extrude_if(h) union() { + rounded_square([length, width], r = cnc_bit_r); + + panel_USBA_hole_positions() + drill(M3_clearance_radius, 0); + } +} + +module panel_USBA() { //! Draw a panel mount USBA connector + vitamin("panel_USBA(): Socket USB A panel mount"); + + width = 12; + length = 40; + length2 = 22; + thickness = 5.5; + height = 33; + height2 = 27; + lead_dia = 10; + r1 = 1.5; + r2 = 5; + height3 = 9.5; + length3 = 17.5; + + l = 17; + w = 13.3; + h = 5.7; + flange_t = 0.4; + h_flange_h = 0.8; + h_flange_l = 11.2; + + v_flange_h = 0.8; + v_flange_l = 3.8; + tongue_w = 10; + tongue_t = 1.3; + + vflip() { + color("dimgrey") { + linear_extrude(height = thickness) + difference() { + hull() + for(side = [-1, 1]) + translate([side * (length / 2 - width / 2), 0]) + circle(d = width); + + square([length3, width + 1], center = true); + + panel_USBA_hole_positions() + circle(M3_clearance_radius); + } + + translate_z(height2) + cylinder(d = lead_dia, h = height - height2); + + hull() { + dx = (length2 / 2 - r2); + dy = (width / 2 - r1); + translate_z(l) + rounded_rectangle([length2, width, 1], r = r1, center = false); + + translate([-dx, -dy, height2 - r2]) + rotate([90, 0, 0]) + rounded_cylinder(r = r2, r2 = r1, h = r1); + + translate([dx, -dy, height2 - r2]) + rotate([90, 0, 0]) + rounded_cylinder(r = r2, r2 = r1, h = r1); + + translate([-dx, dy, height2 - r2]) + rotate([-90, 0, 0]) + rounded_cylinder(r = r2, r2 = r1, h = r1); + + translate([dx, dy, height2 - r2]) + rotate([-90, 0, 0]) + rounded_cylinder(r = r2, r2 = r1, h = r1); + } + + translate_z(height3) + linear_extrude(height = l - height3) + difference() { + rounded_square([length2, width], r = r1); + + square([w - flange_t, h - flange_t], center = true); + } + + linear_extrude(height = height3) + difference() { + rounded_square([length2, width], r = r1); + + square([length3, width + 1], center = true); + } + } + + *cube([12, 4.5, 32], center = true); + + color("silver") { + linear_extrude(height = l) + difference() { + square([w, h], center = true); + + square([w - 2 * flange_t, h - 2 * flange_t], center = true); + } + + translate_z(l - flange_t / 2) + cube([w, h, flange_t], center = true); + + linear_extrude(height = flange_t) + difference() { + union() { + square([h_flange_l, h + 2 * h_flange_h], center = true); + + square([w + 2 * v_flange_h, v_flange_l], center = true); + } + square([w - 2 * flange_t, h - 2 * flange_t], center = true); + } + } + + color("white") + translate([0, h / 2 - 1 - tongue_t / 2, l / 2]) + cube([tongue_w, tongue_t, l], center = true); + } +} + +function tc_length(type) = type[1]; //! Across the lugs +function tc_width(type) = type[2]; //! Width of lugs +function tc_thickness(type) = type[3]; //! Metal thickness +function tc_hole_dia(type) = type[4]; //! Screw hole diameter +function tc_hole_pitch(type) = type[5]; //! Screw hole pitch +function tc_body_length(type) = type[6]; //! Plastic body length +function tc_body_width(type) = type[7]; //! Plastic body width +function tc_body_height(type) = type[8]; //! Plastic body height +function tc_body_inset(type) = type[9]; //! How far metal is inset into the plastic body +function tc_spade_height(type) = type[10]; //! Terminal spade height measured from base +function tc_spade_pitch(type) = type[11]; //! Terminal spade pitch + +module thermal_cutout_hole_positions(type) //! Place children at hole positions + for(side = [-1, 1]) + translate([side * tc_hole_pitch(type) / 2, 0]) + children(); + +module thermal_cutout(type) { //! Draw specified thermal cutout + vitamin(str("thermal_cutout(", type[0], "): Thermal cutout ", type[0])); + + w = tc_width(type); + t = tc_thickness(type); + h = tc_body_height(type); + bw = tc_body_width(type); + bl = tc_body_length(type); + spade = spade6p4; + + color("silver") { + linear_extrude(height = tc_thickness(type)) + difference() { + hull() + for(side = [-1, 1]) + translate([side *(tc_length(type) - w) / 2, 0]) + circle(d = w); + + thermal_cutout_hole_positions(type) + circle(d = tc_hole_dia(type)); + } + + body_inset = tc_body_inset(type); + translate_z((h - body_inset) / 2) + cube([bl - 2 * body_inset, bw + 2 * eps, h - body_inset], center = true); + } + + color("black") + translate_z(h / 2 + eps) + cube([bl, bw, h], center = true); + + for(side = [-1, 1]) + translate([side * tc_spade_pitch(type) / 2, 0, h]) + rotate(90) + spade(spade, tc_spade_height(type) - h); + + translate_z(t) + thermal_cutout_hole_positions(type) + children(); +} diff --git a/vitamins/components.scad b/vitamins/components.scad new file mode 100644 index 0000000..27b4f8a --- /dev/null +++ b/vitamins/components.scad @@ -0,0 +1,50 @@ +// +// 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 . +// + +// +// Resistor model for hot end +// +RWM04106R80J = [ "RWM04106R80J", "Resistor RWM04106R80J 6R8 3W vitreous enamel", 12, 5, 0.8, 30, 5.5, "green", false, false]; +RIE1212UB5C5R6 = [ "RIE1212UB5C5R6", "Resistor UB5C 5R6F 5R6 3W vitreous enamel", 13, 5.9, 0.96, 35, 6.0, "gray", false, false]; +// +// Thermistors +// +Honewell = [ "Honewell", "Thermistor Honeywell 135-104LAC-J01 100K 1%", 4.75, 1.8, 0.5, 28.6, 2, "red", false]; +Epcos = [ "Epcos", "Thermistor Epcos B57560G104F 100K 1%", 4.6, 2.5, 0.3, 67, 2.5, [0.8, 0.8, 0.8, 0.25], true, false]; +EpcosBlue = [ "EpcosBlue", "Thermistor Epcos B57861S104F40 100K 1%", 6.5, 2.41,0.25, 43.5,2.5, "black", true, true]; + +resistors = [Honewell, Epcos, EpcosBlue, RWM04106R80J, RIE1212UB5C5R6]; +// +// Aluminium clad resistors used for heated beds and dummy loads. +// +// l w tab hp vp t hd clr h wire +THS10 = [ "THS10", 17, 17, 4.8, 11.3, 12.4, 2.5, 2.4, 1.9, 9, 30.0]; +THS15 = [ "THS15", 21, 21, 6.0, 14.3, 15.9, 3.2, 2.4, 1.9, 11, 36.5]; +THS25 = [ "THS25", 29, 28, 9.4, 18.3, 19.8, 3.2, 3.3, 2.8, 15, 47]; +THS50 = [ "THS50", 51, 30, 10.7, 39.7, 21.4, 3.2, 3.3, 2.8, 17, 72.5]; + +al_clad_resistors = [ THS10, THS15, THS25, THS50]; +// +// Thermal cutout used on heated beds. +// +TC = ["TC", 31.4, 9.13, 0.8, 3.9, 24, 14.56, 11.3, 14.13, 2, 25, 10]; + +thermal_cutouts = [ TC ]; + +use diff --git a/vitamins/d_connector.scad b/vitamins/d_connector.scad new file mode 100644 index 0000000..655c736 --- /dev/null +++ b/vitamins/d_connector.scad @@ -0,0 +1,191 @@ +// +// 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 . +// + +// +//! D-connectors. Can be any number of ways, male or female, solder buckets, PCB mount or IDC, with or without pillars. +// +include <../core.scad> + +d_pillar_color = grey90; +d_plug_shell_color = grey80; +d_plug_insulator_color = grey20; + +function d_flange_length(type) = type[1]; //! Length of the flange +function d_lengths(type) = type[2]; //! Lengths of the D for plug and socket +function d_hole_pitch(type) = type[3]; //! Mounting hole pitch +function d_widths(type) = type[4]; //! Widths of the D for plug and socket +function d_flange_width(type) = type[5]; //! Width of the flange +function d_height(type) = type[6]; //! From the front to the back of the metal part +function d_front_height(type) = type[7]; //! From the back of the flange to the front +function d_flange_thickness(type) = type[8]; //! Thickness of the flange +function d_ways(type) = type[9]; //! Number of ways +function d_mate_distance(type) = 8.5; //! Spacing when mated +function d_pcb_offset(type) = d_height(type) - d_front_height(type) + 2; //! Height of the back of the flange above the PCB + +function d_slot_length(type) = d_lengths(type)[0] + 3; //! Slot to clear the back + +module d_connector_holes(type) //! Place children at the screw hole positions + for(end = [-1, 1]) + translate([end * d_hole_pitch(type) / 2, 0]) + children(); + +module d_pillar() { //! Draw a pillar for a D-connector + vitamin("d_pillar(): D-type connector pillar"); + rad = 5.37 / 2; + height = 4.5; + screw = 2.5; + screw_length = 8; + color(d_pillar_color) { + translate_z(-screw_length) + cylinder(d = screw, h = screw_length + 1); + + linear_extrude(height = height) + difference() { + circle(r = rad, $fn = 6); + circle(d = screw); + } + } +} + +module d_plug(type, socket = false, pcb = false, idc = false) { //! Draw specified D plug, which can be IDC, PCB or plain solder bucket + hole_r = 3.05 / 2; + dwall = 0.5; + + flange_length = d_flange_length(type); + d_length = d_lengths(type)[socket ? 1 : 0]; + hole_pitch = d_hole_pitch(type); + d_width = d_widths(type)[socket ? 1 : 0]; + flange_width = d_flange_width(type); + front_height = d_front_height(type); + back_height = d_height(type) - front_height; + pins = d_ways(type); + + desc = idc ? "IDC" : pcb ? "PCB mount" : ""; + vitamin(str(socket ? "d_socket(" : "d_plug(", type[0], arg(pcb, false, "pcb"), arg(idc, false, "idc"), + "): D-type ", pins, " way ", desc, socket ? " socket" : " plug")); + + module D(length, width, rad) { + d = width / 2 - rad; + offset = d * sin(10); + + hull() + for(x = [-1, 1], y = [-1, 1]) + translate([x * (length / 2 - rad) + y * x * offset, y * (width / 2 - rad)]) + circle(rad); + } + + module pin_positions() + for($i = [1 : pins]) + translate([($i - (pins + 1) / 2) * 2.77 / 2, ($i % 2 - 0.5) * 2.84]) + children(); + // + // Shell + // + color(d_plug_shell_color) { + linear_extrude(height = d_flange_thickness(type)) + difference() { + rounded_square([flange_length, flange_width], 2); + + d_connector_holes(type) + circle(hole_r); + } + + linear_extrude(height = front_height, convexity = 5) + difference() { + D(d_length, d_width, 2.5); + D(d_length - 2 * dwall, d_width - 2 * dwall, 2.5 - dwall); + } + + if(!idc) + rotate([0,180,0]) + linear_extrude(height = back_height, convexity = 5) + D(d_lengths(type)[0] + 2 * dwall, d_widths(type)[0] + 2 * dwall, 2.5 + dwall); + + } + // + // Insulator + // + color(d_plug_insulator_color) { + translate_z(d_flange_thickness(type) + eps) + rotate([0, 180, 0]) + linear_extrude(height = back_height + 1 + d_flange_thickness(type), convexity = 5) + D(d_length - dwall, d_width - dwall, 2.5 - dwall/2); + + if(socket) + linear_extrude(height = front_height - eps, convexity = 5) + difference() { + D(d_length - dwall, d_width - dwall, 2.5 - dwall/2); + + pin_positions() + circle(r = 0.7); + } + if(idc) { + translate_z(-2.4 / 2) + cube([((pins + 1) / 2) * 2.77 + 6, flange_width, 2.4], center = true); + + translate_z(-14.4 / 2) + cube([pins * 1.27 + 7.29, flange_width, 14.4], center = true); + } + } + // + // Pins + // + color("gold") { + if(!socket) + translate_z(-0.5) + pin_positions() + hull() { + pin_r = 0.5; + cylinder(r = pin_r, h = eps); + + translate_z(front_height - pin_r) + sphere(pin_r); + } + + if(pcb) + rotate([0, 180, 0]) { + linear_extrude(height = back_height + 1 + 4.5) + pin_positions() + circle(r = 0.75 / 2, $fn = 12); + + linear_extrude(height = back_height + 1 + 1) + pin_positions() + circle(r = 0.75, $fn = 12); + } + + if(!pcb && !idc) + rotate([0, 180, 0]) + pin_positions() + rotate(180 + ($i % 2) * 180) + render() difference() { + linear_extrude(height = 8) + difference() { + circle(1); + + circle(0.45); + } + translate([0, 2.1, 8]) + rotate([45, 0, 0]) + cube([3, 3, 3], center = true); + } + } +} + +module d_socket(connector, pcb = false, idc = false) //! Draw specified D socket, which can be IDC, PCB or plain solder bucket + d_plug(connector, true, pcb = pcb, idc = idc); diff --git a/vitamins/d_connectors.scad b/vitamins/d_connectors.scad new file mode 100644 index 0000000..3b49dfe --- /dev/null +++ b/vitamins/d_connectors.scad @@ -0,0 +1,29 @@ +// +// 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 . +// + +// +// D-connectors +// +DCONN9 = ["DCONN9", 30.81, [18, 16.92], 24.99, [9.26, 8.38], 12.55, 10.72, 6.693, 1.12, 9]; +DCONN15 = ["DCONN15", 39.14, [26.25, 25.25], 33.32, [9.26, 8.38], 12.55, 10.72, 6.693, 1.12, 15]; +DCONN25 = ["DCONN25", 53.04, [40, 38.96], 47.04, [9.26, 8.38], 12.55, 10.72, 6.693, 1.12, 25]; + +d_connectors = [DCONN9, DCONN15, DCONN25]; + +use diff --git a/vitamins/display.scad b/vitamins/display.scad new file mode 100644 index 0000000..e4315a4 --- /dev/null +++ b/vitamins/display.scad @@ -0,0 +1,109 @@ +// +// 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 . +// + +// +//! LCD dispays. +// +include <../core.scad> + +use +use + +function display_width(type) = type[2]; //! Width of the metal part +function display_height(type) = type[3]; //! Depth of the metal part +function display_thickness(type) = type[4]; //! Height of the metal part +function display_pcb(type) = type[5]; //! PCB mounted on the back +function display_pcb_offset(type) = type[6]; //! 3D offset of the PCB centre +function display_aperture(type) = type[7]; //! Size of the aperture including its depth +function display_touch_screen(type) = type[8]; //! Touch screen position and size +function display_threads(type) = type[9]; //! Length that studs protrude from the PCB holes +function display_ribbon(type) = type[10]; //! Keep out region for ribbon cable + +function display_ts_thickness(type) = let(ts = display_touch_screen(type)) ts ? ts[1].z : 0; //! Touch screen thickness or 0 + +function display_depth(type) = display_ts_thickness(type) + display_thickness(type) + display_pcb_offset(type).z + pcb_thickness(display_pcb(type)); //! Total thickness including touch screen and PCB + +module display_aperture(type, clearance, clear_pcb = false) { //! Make aperture cutout + aperture = display_aperture(type); + ts = display_touch_screen(type); + pcb = display_pcb(type); + rb = display_ribbon(type); + + translate([aperture[0].x, aperture[0].y, -10]) + cube([aperture[1].x - aperture[0].x, aperture[1].y - aperture[0].y, 20]); + + if(ts) + translate([ts[0].x - clearance, ts[0].y - clearance, -clearance]) + cube([ts[1].x - ts[0].x + 2 * clearance, ts[1].y - ts[0].y + 2 * clearance, ts[1].z + clearance + eps]); + + if(rb) + translate([rb[0].x, rb[0].y,0]) + cube([rb[1].x - rb[0].x, rb[1].y - rb[0].y, ts[1].z + display_depth(type) + 2]); + + if(clear_pcb) + translate([display_pcb_offset(type).x, display_pcb_offset(type).y, display_depth(type) / 2 + 0.5 + display_ts_thickness(type)]) + cube([pcb_length(pcb) + 2 * clearance, pcb_width(pcb) + 2 * clearance, display_depth(type) + 1], center = true); + else + translate_z(display_depth(type) / 2 + 0.5) + cube([display_width(type) + 2 * clearance, display_height(type) + 2 * clearance, display_depth(type) + 1], center = true); +} + +module display(type) { //! Draw specified display + vitamin(str("display(", type[0], "): ", type[1])); + + w = display_width(type); + h = display_height(type); + t = display_thickness(type); + pcb = display_pcb(type); + + gap = display_pcb_offset(type).z; + aperture = display_aperture(type); + ts = display_touch_screen(type); + + not_on_bom() { + translate_z(display_ts_thickness(type)) { + difference() { + color("silver") + rounded_rectangle([w, h, t], 0.5, center = false); + + color("black") + translate([aperture[0].x, aperture[0].y, - eps]) + cube([aperture[1].x - aperture[0].x, aperture[1].y - aperture[0].y, aperture[1].z]); + } + + if(gap) + color("black") + translate_z(t + gap / 2) + cube([w - 1, h - 1, gap], center = true); + + translate([0, 0, display_thickness(type)] + display_pcb_offset(type)) { + pcb(pcb); + + if(display_threads(type)) + pcb_screw_positions(pcb) + vflip() + screw(pcb_screw(pcb), pcb_thickness(pcb) + display_threads(type)); + } + } + if(ts) + color("white", 0.15) + translate([ts[0].x, ts[0].y, 0]) + cube([ts[1].x - ts[0].x, ts[1].y - ts[0].y, ts[1].z - eps]); + } +} diff --git a/vitamins/displays.scad b/vitamins/displays.scad new file mode 100644 index 0000000..52b0606 --- /dev/null +++ b/vitamins/displays.scad @@ -0,0 +1,52 @@ +// +// 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 . +// + +HDMI5PCB = ["", "", 121.11, 77.93, 1.65, 0, 2.2, 0, "mediumblue", false, [[4.6, 4.9], [4.6, -3.73], [97.69, -3.73], [97.69, 4.9]], + [[ 47.245,-2.5, 90, "usb_uA"], + [-53.14, -4.4, 90, "hdmi"], + [ 53.7, 40.6, 0, "chip", 14, 14, 1], + [ 59.8, 25.2, 0, "2p54socket", 13, 2, false, 13.71], + [ 59.8, 10.12, 0, "2p54header", 13, 2, true], + ], + []]; + +HDMI5 = ["HDMI5", "HDMI display 5\"", 121, 76, 2.85, HDMI5PCB, + [0, 0, 1.9], // pcb offst + [[-54, -30.225], [54, 34.575, 0.5]], // aperture + [[-58.7, -34], [58.7, 36.25, 1]], // touch screen + 2, // thread length + [[-2.5, -39], [10.5, -33]], // clearance need for the ts ribbon + ]; + +LCD1602APCB = ["", "", 80, 36, 1.65, 0, 2.9, 5, "green", false, [[-2.5, -2.5], [-2.5, 2.5], [2.5, 2.5], [2.5, -2.5]], + [ [-27.05, - 2.5, 0, "2p54header", 16, 1] + ], + []]; + +LCD1602A = ["LCD1602A", "LCD display 1602A", 71.3, 24.3, 7.0, LCD1602APCB, + [0, 0, 0], // pcb offst + [[-64.5 / 2, -14.5 / 2], [64.5 / 2, 14.5 / 2, 0.6]], // aperture + [], // touch screen + 0, // thread length + [], // clearance need for the ts ribbon + ]; + +displays = [LCD1602A, HDMI5]; + +use diff --git a/vitamins/e3d.scad b/vitamins/e3d.scad new file mode 100644 index 0000000..f463c99 --- /dev/null +++ b/vitamins/e3d.scad @@ -0,0 +1,180 @@ +// +// 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 . +// + +// +// E3D hot ends +// +include <../core.scad> +include +include +include +include + +use <../utils/tube.scad> + +rad_dia = 22; // Diam of the part with ailettes +rad_nb_ailettes = 11; +rad_len = 26; + +nozzle_h = 5; + +module e3d_nozzle(type) { + color("gold") { + rotate_extrude() + polygon([ + [0.2, 0], + [0.2, 2], + [1.5, 2], + [0.65, 0] + ]); + + translate_z(2) + cylinder(d = 8, h = nozzle_h - 2, $fn=6); + } +} + +resistor_len = 22; +resistor_dia = 6; + +heater_width = 16; +heater_length = 20; +heater_height = 11.5; + +heater_x = 4.5; +heater_y = heater_width / 2; + +fan_x_offset = rad_dia / 2 + 4; + +module e3d_resistor(type) { + translate([11 - heater_x, -3 - heater_y, heater_height / 2 + nozzle_h]) { + color("grey") + rotate([-90, 0, 0]) + cylinder(r = resistor_dia / 2, h = resistor_len); + + color("red") + translate([-3.5/2, resistor_len + 3.5/2 + 1, 0]) { + cylinder(d = 3.5, h = 36); + + translate([3.5, 0, 0]) + cylinder(r = 3.5 / 2, h = 36); + } + } +} + +module heater_block(type) { + translate_z(-hot_end_length(type)) { + translate_z(nozzle_h) + color("lightgrey") + translate([-heater_x, -heater_y, 0]) + cube([heater_length, heater_width, heater_height]); + + e3d_resistor(type); + e3d_nozzle(type); + } +} + + + +module e3d_fan_duct(type) { + color("DeepSkyBlue") + render() difference() { + hull() { + translate([-8, -23 / 2, 0]) + cube([eps, 23, 26]); + + translate([fan_x_offset, -30 / 2, 0]) + cube([eps, 30, 30]); + } + cylinder(h = 70, d = rad_dia + 0.1, center = true); // For rad + + translate_z(15) + rotate([0, 90, 0]) + cylinder(d = rad_dia, h = 50); + } +} + +module e3d_fan(type) { + e3d_fan_duct(type); + + translate([fan_x_offset + 5, 0, 15]) + rotate([0, 90, 0]) + not_on_bom() + fan(fan30x10); +} + +module e3d_hot_end(type, filament, naked = false) { + insulator_length = hot_end_insulator_length(type); + inset = hot_end_inset(type); + h_ailettes = rad_len / (2 * rad_nb_ailettes - 1); + + vitamin(str("e3d_hot_end(", type[0], ", ", filament, "): Hot end ", hot_end_part(type), " ", filament, "mm")); + + translate_z(inset - insulator_length) + color(hot_end_insulator_colour(type)) + rotate_extrude() + difference() { + union() { + for (i = [0 : rad_nb_ailettes - 1]) + translate([0, (2 * i) * h_ailettes]) + square([rad_dia / 2, h_ailettes]); + + square([hot_end_insulator_diameter(type) / 2, insulator_length]); + + translate([0, -10]) + square([2, 10]); + } + square([3.2 / 2, insulator_length]); // Filament hole + + translate([hot_end_groove_dia(type) / 2, insulator_length - inset - hot_end_groove(type)]) + square([100, hot_end_groove(type)]); + } + + rotate(90) + heater_block(type); + + if(!naked) + translate_z(inset - insulator_length) + e3d_fan(); +} + +module e3d_hot_end_assembly(type, filament, naked = false) { + bundle = 3.2; + + e3d_hot_end(type, filament, naked); + + // Wire and ziptie + if(!naked) + rotate(10) { + dia = hot_end_insulator_diameter(type); + scale([1, (bundle + dia) / dia]) + translate([0, -bundle / 2, -7]) + rotate(-110) + ziptie(small_ziptie, dia / 2); + + translate([0, -dia / 2 - bundle / 2, 20]) + scale([0.7, bundle / 6.4]) + difference() { + tubing(HSHRNK64, 60); + + translate_z(20) + cube([10, 10, 60], center = true); + } + } + +} diff --git a/vitamins/fan.scad b/vitamins/fan.scad new file mode 100644 index 0000000..abb940f --- /dev/null +++ b/vitamins/fan.scad @@ -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 . +// + +// +//! Axial fans. +//! +//! Can draw three styles: solid, open frame and open frame with screw bosses. +// +include <../core.scad> +use +use +use +use <../utils/tube.scad> + +fan_colour = grey20; + +function fan_width(type) = type[0]; //! Width of square +function fan_depth(type) = type[1]; //! Depth of fan +function fan_bore(type) = type[2]; //! Diameter of the hole for the blades +function fan_hole_pitch(type) = type[3]; //! Screw hole pitch +function fan_screw(type) = type[4]; //! Screw type +function fan_hub(type) = type[5]; //! Diameter of the hub +function fan_thickness(type) = type[6]; //! Thickness of the frame +function fan_outer_diameter(type) = type[7]; //! Outside diameter of the frame +function fan_blades(type) = type[8]; //! The number of blades +function fan_boss_d(type) = type[9]; //! Diameter of the screw bosses +function fan_aperture(type) = type[10] ? type[10] : fan_bore(type); //! Optional diameter for the aperture, which can be bigger than the bore it has flared corners. + +module fan(type) { //! Draw specified fan, origin in the centre + width = fan_width(type); + depth = fan_depth(type); + thickness = fan_thickness(type); + hole_pitch = fan_hole_pitch(type); + corner_radius = width / 2 - hole_pitch; + screw = fan_screw(type); + + vitamin(str("fan(fan", width, "x", depth, "): Fan ", width, "mm x ", depth, "mm")); + + module squarish(s, n) { + polygon([ + for(i = [0 : n]) [i * s.x / n, s.y + (i % 2) * eps], + for(i = [0 : n]) [s.x - i * s.x / n, (i % 2) * eps], + ]); + } + + module shape() + difference() { + //overall outside + rounded_square([width, width], corner_radius); + + //main inside bore, less hub + difference() { + circle(fan_bore(type) / 2); + circle(fan_hub(type) / 2); + } + + //Mounting holes + fan_hole_positions(type) + circle(screw_clearance_radius(screw)); + } + + color(fan_colour) { + middle = depth - 2 * thickness; + if(middle > 0) { + for(z = [-1, 1]) + translate_z(z * (depth - thickness) / 2) + linear_extrude(height = thickness, center = true) + shape(); + + linear_extrude(height = middle, center = true) + difference() { + shape(); + difference() { + circle(sqrt(2) * width / 2); + circle(d = fan_outer_diameter(type)); + + if(fan_boss_d(type)) + for(i = [-1, 1]) + hull() + for(side = [-1, 1]) + translate([hole_pitch * side * i, hole_pitch * side]) + circle(d = fan_boss_d(type)); + } + } + } + else + linear_extrude(height = depth, center = true) + shape(); + + // Blades + blade_ir = fan_hub(type) / 2 - 1; + blade_len = fan_bore(type) / 2 - 0.75 - blade_ir; + linear_extrude(height = depth - 1, center = true, convexity = 4, twist = -30, slices = round(depth / 2)) + for(i = [0 : fan_blades(type) - 1]) + rotate((360 * i) / fan_blades(type)) + translate([blade_ir, -1.5 / 2]) + squarish([blade_len, 1.5], round(blade_len / 2)); + } +} + +module fan_hole_positions(type, z = undef) { //! Position children at the screw hole positions + hole_pitch = fan_hole_pitch(type); + for(x = [-hole_pitch, hole_pitch]) + for(y = [-hole_pitch, hole_pitch]) + translate([x, y, is_undef(z) ? fan_depth(type) / 2 : z]) + children(); +} + +module fan_holes(type, poly = false, screws = true, h = 100) { //! Make all the holes for the fan, or just the aperture if ```screws``` is false. Set ```poly``` true for poly_holes. + hole_pitch = fan_hole_pitch(type); + screw = fan_screw(type); + + extrude_if(h) { + if(screws) + fan_hole_positions(type, z = 0) + if(poly) + poly_circle(r = screw_clearance_radius(screw)); + else + drill(screw_clearance_radius(screw), 0); + + difference() { + intersection() { + square(fan_bore(type), center = true); + + circle(d = fan_aperture(type)); + } + if(screws) + fan_hole_positions(type, z = 0) + circle(d = washer_diameter(screw_washer(screw)) + 1); + } + } +} + +function nut_and_washer_thickness(screw, nyloc) = washer_thickness(screw_washer(screw)) + nut_thickness(screw_nut(screw), nyloc); +function fan_screw_depth(type) = fan_boss_d(type) ? fan_depth(type) : fan_thickness(type); +function fan_screw_length(type, thickness) = screw_longer_than(thickness + fan_screw_depth(type) + nut_and_washer_thickness(fan_screw(type), true)); //! Screw length required + +module fan_assembly(type, thickness, include_fan = true) { //! Fan with its fasteners + translate_z(-fan_depth(type) / 2) { + if(include_fan) + fan(type); + + screw = fan_screw(type); + nut = screw_nut(screw); + fan_hole_positions(type) { + translate_z(thickness) + screw_and_washer(screw, fan_screw_length(type, thickness)); + + translate_z(include_fan ? -fan_screw_depth(type) : 0) + vflip() + nut(nut, true); + } + } +} diff --git a/vitamins/fans.scad b/vitamins/fans.scad new file mode 100644 index 0000000..55b78ce --- /dev/null +++ b/vitamins/fans.scad @@ -0,0 +1,46 @@ +// +// 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 . +// + +include + +// w d b h s h t o b b a +// i e o o c u h u l o p +// d p r l r b i t a s p +// t t e e e c e d s e +// h h w d k r e r +// p i n s d t +// i a e d u +// t s i r +// c s a e +// h +// +fan120x25= [120,25, 116,52.5, M4_dome_screw, 41, 4, 140, 9, 0, 137]; +fan80x38 = [80, 38, 75, 35.75, M4_dome_screw, 40, 4.3, 84, 7, 0, 85]; +fan80x25 = [80, 25, 75, 35.75, M4_dome_screw, 40, 4.3, 84, 7, 0, 85]; +fan70x15 = [70, 15, 66, 30.75, M4_dome_screw, 29, 3.8, 70 ,7, 0, undef]; +fan60x25 = [60, 25, 57, 25, M4_dome_screw, 31.5, 3.6, 64, 7, 0, 63]; +fan60x15 = [60, 15, 57, 25, M4_dome_screw, 29, 2.4, 60, 7, 7.7, 63]; +fan50x15 = [50, 15, 48, 20, M4_dome_screw, 25, 12.5,100,7, 0, undef]; +fan40x11 = [40, 11, 37, 16, M3_dome_screw, 25, 7.5,100, 9, 0, undef]; +fan30x10 = [30, 10, 27, 12, M3_dome_screw, 17, 10, 100, 5, 0, undef]; +fan25x10 = [25, 10, 24, 10, M2p5_pan_screw, 16, 10, 100, 5, 0, undef]; + +fans = [fan25x10, fan30x10, fan40x11, fan50x15, fan60x15, fan60x25, fan70x15, fan80x25, fan80x38, fan120x25]; + +use diff --git a/vitamins/fuseholder.scad b/vitamins/fuseholder.scad new file mode 100644 index 0000000..56e77f0 --- /dev/null +++ b/vitamins/fuseholder.scad @@ -0,0 +1,133 @@ +// +// 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 . +// + +// +//! 20mm panel mount fuse holder. +// +include <../core.scad> +include +use <../utils/tube.scad> + +module fuseholder_hole(h = 100) //! Hole with flats for fuseholder + extrude_if(h) + intersection() { + circle(d = 12); + + square([100, 11], center = true); + } + +function fuseholder_diameter() = 18.8; //! Outside diameter of flange + +module fuseholder(thickness) { //! Fuseholder with nut in place for specified panel thickness + vitamin(str("fuseholder(6): Fuse holder 20mm")); + flange_d = fuseholder_diameter(); + flange_t = 2; + height = 33.2; + thread_d = 11.7; + thread = 15; + bot_d = 10.4; + top_d = 8.7; + flat = 10.8; + nut_d = 18.8; + nut_t = 6; + nut_flange_t = 1.5; + spade = 5.4; + contact_slot_z = 20; + contact_slot_w = 3.2; + contact_slot_d = 7; + + contact_w = 2.8; + contact_t = 0.3; + contact_l1 = 11; + contact_l2 = 6; + // + // Nut + // + vflip() + translate_z(thickness) + explode(height) + color("dimgrey") { + tube(or = nut_d / 2, ir = 5, h = nut_flange_t, center = false); + + linear_extrude(height = nut_t) + difference() { + circle(d = nut_d, $fn = 6); + + circle(5); + } + } + // + // Body + // + explode(height + 5, offset = -height - 4) { + color("dimgrey") { + tube(or = flange_d / 2, ir = 5.2, h = flange_t, center = false); + + cylinder(r = 5, h = flange_t - 1); + + linear_extrude(height = flange_t) + difference() { + circle(r = 5); + + square([8, 1.5], center = true); + } + + vflip() { + linear_extrude(height = thread) + intersection() { + circle(d = thread_d); + + square([100, 10.8], center = true); + } + render() difference() { + translate_z(thread) + cylinder(d1 = bot_d, d2 = top_d, h = height - flange_t - thread); + + for(side = [-1, 1]) + translate([side * (contact_slot_d / 2 + 1) - 1, -contact_slot_w / 2, contact_slot_z]) + cube([2, contact_slot_w, 100]); + } + } + } + // + // Side contacts + // + color("silver") vflip() + for(side = [-1, 1]) + translate([side * contact_slot_d / 2, 0, contact_slot_z]) + rotate([0, -70, 90 - side * 90]) + linear_extrude(height = contact_t, center = true) difference() { + hull() { + square([eps, contact_w], center = true); + + translate([(side > 0 ? contact_l1 : contact_l2) - contact_w / 2, 0]) + circle(d = contact_w); + } + translate([(side > 0 ? contact_l1 : contact_l2) - contact_w / 2, 0]) + circle(d = 1); + } + // + // Bottom contact + // + translate_z(-height + flange_t) + vflip() + rotate(45) + spade(spade3, spade); + } +} diff --git a/vitamins/hot_end.scad b/vitamins/hot_end.scad new file mode 100644 index 0000000..0132d76 --- /dev/null +++ b/vitamins/hot_end.scad @@ -0,0 +1,53 @@ +// +// 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 . +// + +// +//! Hot end models. The E3D models were originally contributed to Mendel90 by Philippe LUC @philfifi +//! +//! Needs updating as mostly obsolete versions. +// +include <../core.scad> + +function hot_end_style(type) = type[1]; //! Basic type, jhead or e3d +function hot_end_part(type) = type[2]; //! Description +function hot_end_total_length(type) = type[3]; //! Length from nozzle tip to the top +function hot_end_inset(type) = type[4]; //! The length that goes into the mounting +function hot_end_insulator_diameter(type) = type[5]; //! Outside diameter +function hot_end_insulator_length(type) = type[6]; //! Length of the insulator +function hot_end_insulator_colour(type) = type[7]; //! Colour of the insulator +function hot_end_groove_dia(type) = type[8]; //! Groove internal diameter +function hot_end_groove(type) = type[9]; //! Groove length +function hot_end_duct_radius(type) = type[10]; //! Require radius to clear the heater block +function hot_end_duct_offset(type) = type[11]; //! Offset of circular duct centre from the nozzle +function hot_end_need_cooling(type) = hot_end_style(type) != e3d; //! Has own fan so don't need cooling hole in the duct +function hot_end_duct_height_nozzle(type) = type[12]; //! Duct height at nozzle end +function hot_end_duct_height_fan(type) = type[13]; //! Duct height at fan end + +function hot_end_length(type) = hot_end_total_length(type) - hot_end_inset(type); //! The amount the hot end extends below its mounting + +use +use + +module hot_end(type, filament, naked = false) { //! Draw specified hot end + if(hot_end_style(type) == jhead) + jhead_hot_end_assembly(type, filament, naked); + + if(hot_end_style(type) == e3d) + e3d_hot_end_assembly(type, filament, naked); +} diff --git a/vitamins/hot_ends.scad b/vitamins/hot_ends.scad new file mode 100644 index 0000000..78fd6fc --- /dev/null +++ b/vitamins/hot_ends.scad @@ -0,0 +1,44 @@ +// +// 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 . +// + +// +// Hot end descriptions +// +// s p l i d i l c s g g d d d a d a +// t a e n i n e o c r r u u u t u t +// y r n s a s n l r o o c c c c +// l t g e u g o e o o t t t n t f +// e t t l t u w v v o a +// h a h r e e r o h z h n +// t p a f e z e +// o i d w d f i l i +// r t i i i s g e g +// c a d u e h h +// h t s t t t +// h +// +JHeadMk4 = ["JHeadMk4", jhead, "JHead MK4", 64, 5.1, 16, 50, grey20, 12, 4.64, 14, [0, 2.94, -5], 20, 20]; +JHeadMk5 = ["JHeadMk5", jhead, "JHead MK5", 51.2, 5.1, 16, 40, grey20, 12, 4.64, 13, [0, 2.38, -5], 20, 20]; +E3Dv5 = ["E3Dv5", e3d, "E3D V5 direct", 70, 3.7, 16, 50.1, "silver", 12, 6, 15, [1, 5, -4.5], 14.5, 28]; +E3Dv6 = ["E3Dv6", e3d, "E3D V6 direct", 62, 3.7, 16, 42.7, "silver", 12, 6, 15, [1, 5, -4.5], 14, 21]; +E3D_clone = ["E3D_clone", e3d, "E3D clone aliexpress",66, 6.8, 16, 46, "silver", 12, 5.6, 15, [1, 5, -4.5], 14.5, 21]; + +hot_ends = [JHeadMk5, E3Dv5, E3Dv6, E3D_clone]; + +use diff --git a/vitamins/iec.scad b/vitamins/iec.scad new file mode 100644 index 0000000..0c7152e --- /dev/null +++ b/vitamins/iec.scad @@ -0,0 +1,228 @@ +// +// 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 . +// + +// +//! IEC mains inlets and outlet. +// +include <../core.scad> +use +use +use +use +include + +function iec_part(type) = type[1]; //! Description +function iec_screw(type) = type[2]; //! Screw type +function iec_pitch(type) = type[3]; //! Screw hole pitch +function iec_slot_w(type) = type[4]; //! Body width +function iec_slot_h(type) = type[5]; //! Body height +function iec_slot_r(type) = type[6]; //! Body corner radius +function iec_bezel_w(type) = type[7]; //! Bezel width +function iec_bezel_h(type) = type[8]; //! Bezel height +function iec_bezel_r(type) = type[9]; //! Bezel corner radius +function iec_bezel_t(type) = type[10]; //! Bezel thickness +function iec_flange_w(type) = type[11]; //! Flange width not including the lugs +function iec_flange_h(type) = type[12]; //! Flange height +function iec_flange_r(type) = type[13]; //! Flange corner radius +function iec_flange_t(type) = type[14]; //! Flange thickness +function iec_width(type) = type[15]; //! Widest part including the lugs +function iec_depth(type) = type[16]; //! Depth of the body below the flange +function iec_spades(type) = type[17]; //! Spade type +function iec_male(type) = type[18]; //! True for an outlet + +insert_overlap = 1.1; // chosen to make cap screws 10mm long. + +module iec(type) { //! Draw specified IEC connector + vitamin(str("iec(", type[0], "): ", iec_part(type))); + + pin_w = 2; + pin_d = 4; + pin_h1 = 12; + pin_h2 = 15; + pin_chamfer = 1; + + module pin(h) + color("silver") + hull() { + translate_z(h / 2) + cube([pin_w - pin_chamfer, pin_d - pin_chamfer, h], center = true); + + translate_z((h - pin_chamfer) / 2) + cube([pin_w, pin_d, h - pin_chamfer], center = true); + } + + socket_w = 24; + socket_w2 = 14; + socket_h = 16.5; + socket_h2 = 12; + socket_d = 17; + socket_r = 3; + socket_r2 = 0.5; + socket_offset = iec_bezel_h(type) / 2 - socket_h / 2 - (iec_bezel_w(type) - socket_w) / 2; + + module socket_shape() + hull() + for(side = [-1, 1]) { + translate([side * (socket_w / 2 - socket_r), -socket_h / 2 + socket_r]) + circle(socket_r); + + translate([side * (socket_w / 2 - socket_r2), -socket_h / 2 + socket_h2 + socket_r2]) + circle(socket_r2); + + translate([side * (socket_w2 / 2 - socket_r2), socket_h / 2 - socket_r2]) + circle(socket_r2); + } + + module oriffice_shape() + translate([0, socket_offset]) + if(iec_male(type)) + difference() { + offset(3) + socket_shape(); + + difference() { + offset(-1) socket_shape(); + + translate([0, 2]) + square([2.4, 5], center = true); + + for(side = [-1, 1]) + translate([side * 7, -2]) + square([2.4, 5], center = true); + } + } + else + socket_shape(); + + color(grey20) { + // Flange + flange_t = iec_flange_t(type); + linear_extrude(height = flange_t) + difference() { + hull() { + rounded_square([iec_flange_w(type), iec_flange_h(type)], iec_flange_r(type)); + + iec_screw_positions(type) + circle(d = iec_width(type) - iec_pitch(type)); + } + oriffice_shape(); + + iec_screw_positions(type) + circle(socket_r); + } + head_r = screw_head_radius(iec_screw(type)); + screw_r = screw_clearance_radius(iec_screw(type)); + iec_screw_positions(type) + rotate_extrude() + difference() { + translate([screw_r, 0]) + square([socket_r - screw_r, flange_t]); + + translate([0, flange_t - head_r]) + rotate(45) + square(10); + } + // Bezel + translate_z(iec_flange_t(type)) + linear_extrude(height = iec_bezel_t(type)) + difference() { + rounded_square([iec_bezel_w(type), iec_bezel_h(type)], iec_bezel_r(type)); + + oriffice_shape(); + } + + // Body + h = socket_d - iec_flange_t(type) - iec_bezel_t(type); + translate_z(-h) + linear_extrude(height = h) + difference() { + rounded_square([iec_slot_w(type), iec_slot_h(type)], iec_slot_r(type)); + oriffice_shape(); + } + // Back + translate_z(-iec_depth(type)) + rounded_rectangle([iec_slot_w(type), iec_slot_h(type), iec_depth(type) - h], iec_slot_r(type), center = false); + } + if(!iec_male(type)) + translate([0, socket_offset, iec_flange_t(type) + iec_bezel_t(type) - socket_d]) { + translate([0, 2]) + pin(pin_h2); + + for(side = [-1, 1]) + translate([side * 7, -2]) + pin(pin_h1); + } + for(spade = iec_spades(type)) + translate([spade[2], spade[3], -iec_depth(type)]) + rotate([180, 0, spade[4]]) + spade(spade[0], spade[1]); +} + +module iec_screw_positions(type) //! Position children at the screw holes + for(side = [-1, 1]) + translate([side * iec_pitch(type) / 2, 0]) + children(); + +module iec_holes(type, h = 100, poly = false, horizontal = false, insert = false) { //! Drill the required panel holes + clearance = 0.2; + + iec_screw_positions(type) + if(insert) + insert_hole(screw_insert(iec_screw(type)), insert_overlap, horizontal = horizontal); + else + if(horizontal) + teardrop_plus(r = screw_clearance_radius(iec_screw(type)), h = h); + else + if(poly) + poly_cylinder(r = screw_clearance_radius(iec_screw(type)), h = h, center = true); + else + drill(screw_clearance_radius(iec_screw(type)), h); + + extrude_if(h) + hull() + for(x = [-1, 1], y = [-1, 1], sag = horizontal && y > 1 ? layer_height : 0) + translate([x * (iec_slot_w(type) / 2 - iec_slot_r(type)), y * (iec_slot_h(type) / 2 - iec_slot_r(type) + sag )]) + if(horizontal) + teardrop(0, iec_slot_r(type) + clearance / 2 + layer_height / 4); + else + drill(iec_slot_r(type) + clearance / 2, 0); +} + +module iec_assembly(type, thickness) { //! Assembly with fasteners given panel thickness + screw = iec_screw(type); + washer = screw_washer(screw); + nut = screw_nut(screw); + insert = screw_insert(screw); + screw_length = thickness ? screw_longer_than(iec_flange_t(type) + thickness + washer_thickness(washer) + nut_thickness(nut, true)) + : screw_shorter_than(iec_flange_t(type) + insert_hole_length(insert) + insert_overlap); + + iec(type); + + iec_screw_positions(type) { + translate_z(iec_flange_t(type)) + screw(screw, screw_length); + + if(thickness) + translate_z(-thickness) + vflip() + nut_and_washer(nut, true); + else + insert(insert); + } +} diff --git a/vitamins/iecs.scad b/vitamins/iecs.scad new file mode 100644 index 0000000..d3e0ea2 --- /dev/null +++ b/vitamins/iecs.scad @@ -0,0 +1,47 @@ +// +// 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 . +// +include +include + +fused_spades = [[spade6p4, 14, -7, 0, 0], + [spade6p4, 14, 7, 0, 0], + [spade6p4, 14, 0, 11, 0], + [spade4p8, 8.5, -7, -9, 90], + [spade4p8, 8.5, 7, -9, 90]]; + +inlet_spades = [[spade6p4, 9, -7, -5.5, 0], + [spade6p4, 9, 7, -5.5, 0], + [spade6p4, 9, 0, 5.5, 0]]; +// +// p s p s s s b b b b f f f f w d s m +// a c i l l l e e e e l l l l i e p a +// r r t o o o z z z z a a a a d p a l +// t e c t t t e e e e n n n n t t d e +// w h l l l l g g g g h h e +// w h r e e e e s +// w h r t +// w h r t +// +IEC_fused_inlet = ["IEC_fused_inlet", "IEC fused inlet", M3_cs_cap_screw, 36, 27.3, 31.2, 3, 28, 31, 2, 2.5, 30, 33, 4, 2.5, 44, 21, fused_spades, false ]; +IEC_inlet = ["IEC_inlet", "IEC inlet", M3_cs_cap_screw, 40, 28.2, 20.2, 3, 28, 20.5, 4, 2.5, 37, 23, 1, 2.5, 48, 14, inlet_spades, false ]; +IEC_inlet_atx = ["IEC_inlet_atx", "IEC inlet for ATX", M3_cs_cap_screw, 40, 27.0, 19.0, 3, 30, 22, 2, 2.0, 30, 22, 2, 4.0, 50, 13, inlet_spades, false ]; +IEC_outlet = ["IEC_outlet", "IEC outlet", M3_cs_cap_screw, 40, 32, 24, 3, 28, 20.5, 2, 0.0, 29, 29, 2, 2.9, 50, 23, inlet_spades, true ]; + +iecs = [IEC_inlet, IEC_inlet_atx, IEC_fused_inlet, IEC_outlet]; +use diff --git a/vitamins/insert.scad b/vitamins/insert.scad new file mode 100644 index 0000000..f85a195 --- /dev/null +++ b/vitamins/insert.scad @@ -0,0 +1,104 @@ +// +// 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 . +// + +// +//! Heatfit threaded inserts. Can be pushed into thermoplastics using a soldering iron with a conical bit set to 200°C. +// +include <../core.scad> + +function insert_length(type) = type[1]; //! Length +function insert_outer_d(type) = type[2]; //! Outer diameter at the top +function insert_hole_radius(type) = type[3] / 2; //! Radius of the required hole in the plastic +function insert_screw_diameter(type) = type[4]; //! Screw size +function insert_barrel_d(type) = type[5]; //! Diameter of the main barrel +function insert_ring1_h(type) = type[6]; //! Height of the top and middle rings +function insert_ring2_d(type) = type[7]; //! Diameter of the middle ring +function insert_ring3_d(type) = type[8]; //! Diameter of the bottom ring + +function insert_hole_length(type) = round_to_layer(insert_length(type)); + +module insert(type) { //! Draw specified insert + length = insert_length(type); + ring1_h = insert_ring1_h(type); + + chamfer1 = (insert_ring2_d(type) - insert_barrel_d(type)) / 2; + chamfer2 = (insert_ring3_d(type) - insert_barrel_d(type)) / 2; + ring2_h = ring1_h + chamfer1; + gap = (length - ring1_h - ring2_h- chamfer2) / 3; + + vitamin(str("insert(", type[0], "): Heatfit insert M", insert_screw_diameter(type))); + $fn = 64; + explode(20, offset =[0, 0, -5]) color(brass) translate_z(eps) { + vflip(){ + r1 = insert_screw_diameter(type) / 2; + r2 = insert_barrel_d(type) / 2; + r3 = insert_ring3_d(type) / 2; + r4 = insert_ring2_d(type) / 2; + r5 = insert_outer_d(type) / 2; + h1 = ring1_h; + h2 = ring1_h + gap; + h3 = ring1_h + gap + ring2_h; + h4 = ring1_h + gap + ring2_h + gap; + rotate_extrude() + polygon([ + [r1, 0], + [r1, length], + [r2, length], + [r3, length - chamfer2], + [r3, h4], + [r2, h4], + [r2, h3], + [r4, h3 - chamfer1], + [r4, h2], + [r2, h2], + [r2, h1], + [r5, h1], + [r5, 0], + ]); + } + } +} + +module insert_hole(type, counterbore = 0, horizontal = false) { //! Make a hole to take an insert, ```counterbore``` is the extra length for the screw + h = insert_hole_length(type); + + render() if(horizontal) { + teardrop_plus(r = insert_hole_radius(type), h = 2 * h); + + if(counterbore) + teardrop_plus(r = insert_screw_diameter(type) / 2 + 0.1, h = 2 * (h + counterbore)); + } + else { + poly_cylinder(r = insert_hole_radius(type), h = 2 * h, center = true); + + if(counterbore) + poly_cylinder(r = insert_screw_diameter(type) / 2 + 0.1, h = 2 * (h + counterbore), center = true); + } +} + +module insert_boss(type, z, wall = 2 * extrusion_width) { //! Make a boss to take an insert + difference() { + ir = insert_hole_radius(type); + linear_extrude(height = z) + poly_ring(corrected_radius(ir) + wall, insert_screw_diameter(type) / 2 + 0.1); + + translate_z(z) + insert_hole(type, max(0, z - insert_hole_length(type) - 2 * layer_height)); + } +} diff --git a/vitamins/inserts.scad b/vitamins/inserts.scad new file mode 100644 index 0000000..4d3362c --- /dev/null +++ b/vitamins/inserts.scad @@ -0,0 +1,43 @@ +// +// 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 . +// + +// +// Threaded inserts +// +// l o h s b r r r +// e u o c a i i i +// n t l r r n n n +// g e e e r g g g +// t r w e 1 2 3 +// h d l +// d d h d d +// d +// +F1BM2 = [ "F1BM", 4.0, 3.6, 3.2, 2, 3.0, 1.0, 3.4, 3.1 ]; +F1BM2p5 = [ "F1BM2p5", 5.8, 4.6, 4.0, 2.5, 3.65, 1.6, 4.4, 3.9 ]; +F1BM3 = [ "F1BM3", 5.8, 4.6, 4.0, 3, 3.65, 1.6, 4.4, 3.9 ]; +F1BM4 = [ "F1BM4", 8.2, 6.3, 5.6, 4, 5.15, 2.3, 6.0, 5.55 ]; + +inserts = [ F1BM2, F1BM2p5, F1BM3, F1BM4 ]; + +function screw_insert(screw, i = 0) = let(d = screw_radius(screw) * 2) + i >= len(inserts) ? undef + : insert_screw_diameter(inserts[i]) == d ? inserts[i] + : screw_insert(screw, i + 1); +use diff --git a/vitamins/jack.scad b/vitamins/jack.scad new file mode 100644 index 0000000..7e5b784 --- /dev/null +++ b/vitamins/jack.scad @@ -0,0 +1,284 @@ +// +// 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 . +// + +// +//! 4mm jack sockets and binding posts. Each has a colour for the BOM entry and an optional alternative colour for display. +//! E.g. a "brown" socket for mains live needs to be displayed as "sienna" to look realistic. +// +include <../core.scad> +include +include +use <../utils/tube.scad> +use <../utils/rounded_cylinder.scad> +use + +function jack_4mm_hole_radius() = 8/2; //! Panel hole radius for 4mm jack + +module jack_4mm(colour, thickness, display_colour = false) { //! Draw a 4mm jack socket with nut positioned for specified panel thickness + vitamin(str("jack_4mm(\"", colour, "\", 3", arg(display_colour, false), "): 4mm jack socket ", colour)); + flange_d = 10.6; + flange_t = 3; + flange_id = 4.6; + length = 28.5; + sleaved = 15; + sleaved_d = 6.4; + thread = 10.4; + thread_d = 8; + nut_d = 9.8; + nut_t = 3; + barrel_d = 5.4; + barrel = 18.5; + spade = 7; + + explode(length, offset = -length + flange_t) { + color(display_colour ? display_colour : colour) rotate_extrude() difference() { + union() { + square([flange_d / 2, flange_t]); + + translate([0, -sleaved]) + square([sleaved_d / 2, sleaved]); + + } + square([flange_id, 100], center = true); + } + color("silver") rotate_extrude() difference() { + union() { + translate([0, -thread]) + square([thread_d / 2, thread]); + + *translate([0, -nut_t - thickness]) + square([nut_d / 2, nut_t]); + + translate([0, -barrel]) + square([barrel_d / 2, barrel]); + } + square([4, 2 * (barrel - 1)], center = true); + } + translate_z(-length + flange_t + spade) + vflip() + spade(spade4p8l, spade); + } + translate_z(-thickness) + explode(-length) + color("silver") + vflip() + tube(ir = thread_d / 2, or = nut_d / 2, h = nut_t, center = false); +} + +function jack_4mm_shielded_hole_radius() = 12/2; //! Panel hole radius for 4mm shielded jack + +module jack_4mm_shielded(colour, thickness, display_colour = false) { //! Draw a 4mm shielded jack + vitamin(str("jack_4mm_shielded(\"", colour, "\", 3", arg(display_colour, false), "): 4mm shielded jack socket ", colour)); + flange_d = 14.5; + flange_t = 2.5; + flange_id = 4.6; + sleaved = 21; + sleaved_d = 10.7; + thread = 14; + thread_d = 11.7; + nut_d = 14.4; + nut_t = 5; + length = 32; + spade = 8.5; + + explode(length, offset = -length + flange_t) { + color(display_colour ? display_colour : colour) { + rounded_cylinder(r = flange_d / 2, h = flange_t, r2 = 1, ir = 4.5); + + rotate_extrude() difference() { + union() { + translate([0, -sleaved]) + square([sleaved_d / 2, sleaved + flange_t]); + + translate([0, -thread]) + square([thread_d / 2, thread]); + } + square([flange_id, 100], center = true); + + difference() { + square([9, 2 * sleaved - 1], center = true); + square([6, 2 * sleaved], center = true); + } + } + } + color("silver") + translate_z(-length + flange_t + spade - 0.5) + cylinder(d = 4.8, h = 0.5); + + translate_z(-length + flange_t + spade) + vflip() + spade(spade4p8ll, spade); + } + + translate_z(-thickness) + explode(-length) + color("silver") + vflip() + tube(ir = thread_d / 2, or = nut_d / 2, h = nut_t, center = false); + +} + +function post_4mm_diameter() = 13; //! Outer diameter of 4mm binding post + +post_4mm_hole_radius = 7 / 2; +post_4mm_spigot_w = 1.1; +post_4mm_spigot_l = 1.2; +post_4mm_spigot_h = 2.5; + +module post_4mm_hole(h = 100, poly = false) { //! Drill hole for 4mm binding post + extrude_if(h) union() { + r = cnc_bit_r + eps; + if(poly) + poly_circle(post_4mm_hole_radius); + else + drill(post_4mm_hole_radius, 0); + + hull() { + translate([0, post_4mm_hole_radius + post_4mm_spigot_l - r]) + drill(r, 0); + + drill(r, 0); + } + } +} + +module post_4mm(colour, thickness, display_colour = false) { //! Draw a 4mm binding post + vitamin(str("post_4mm(\"", colour, "\", 3", arg(display_colour, false), "): 4mm jack binding post ", colour)); + + actual_colour = display_colour ? display_colour : colour; + d = post_4mm_diameter(); + base_h = 5; + collar_t = post_4mm_spigot_h; + + post_od = 9.5; + post_metal = 0.2; + thread_d = 3.5; + thread_l = 15; + post_d = 7; + post_h = 14; + + ringterm = ["", 6.3, 3.8, 16.7, 3, 1.6, 0.3, M4_dome_screw]; + + module washer() { + washer_t = 0.65; + + tube(or = 7.6 / 2, ir = thread_d / 2, h = washer_t, center = false); + + translate_z(washer_t) + children(); + } + + module nut() { + nut_t = 2.3; + + linear_extrude(height = nut_t) difference() { + circle(d = 6.3 / cos(30), $fn = 6); + + circle(d = thread_d); + } + + translate_z(nut_t) + children(); + } + + module spigot() + hull() + for(end = [-1, 1]) + translate([0, post_4mm_hole_radius + end * (post_4mm_spigot_l - post_4mm_spigot_w / 2)]) + circle(d = post_4mm_spigot_w); + + explode(20, offset = -thread_l) { + color(actual_colour) { + cylinder(d = d, h = base_h); + + translate_z(-collar_t) + linear_extrude(height = base_h) { + circle(post_4mm_hole_radius - 0.1); + + spigot(); + } + + translate_z(base_h + 1) + for(i = [0 : 7]) + rotate(i * 360 / 8) + render() difference() { + rotate_extrude(angle = 360 / 8) + polygon([ + [0, 0], + [0, 2], + [post_d / 2, 2], + [post_d / 2, 17.5], + [11 / 2, 17.5], + [12.5 / 2, 0] + ]); + + rotate(180 /8) + hull() { + translate([6.5, 0, 3]) + sphere(d = 2.5); + + translate([6, 0, 17.5]) + cylinder(d = 2.5, h = eps); + } + } + } + + color("silver") { + translate_z(post_metal) + cylinder(d = post_od, h = base_h); + + translate_z(base_h + post_metal + 0.1) + cylinder(d = post_od, h = 2); + + rotate_extrude() difference() { + square([post_d / 2, base_h + post_metal + post_h]); + + translate([0, base_h + post_metal + 1]) + square([2, post_h]); + + } + vflip() + cylinder(d = thread_d, h = thread_l); + } + } + explode(-15) + color(actual_colour) { + translate_z(-thickness - base_h) { + linear_extrude(height = base_h) + difference() { + circle(d = d); + + circle(post_4mm_hole_radius); + + offset(0.1) spigot(); + } + tube(or = d / 2, ir = thread_d / 2, h = collar_t, center = false); + } + } + translate_z(-thickness - base_h) + explode(-20, true) + color("silver") + vflip() + not_on_bom() + washer() + explode(5, true) nut() + explode(5, true) ring_terminal(ringterm) + explode(5, true) washer() + explode(5, true) nut(); +} diff --git a/vitamins/jhead.scad b/vitamins/jhead.scad new file mode 100644 index 0000000..a693419 --- /dev/null +++ b/vitamins/jhead.scad @@ -0,0 +1,202 @@ +// +// 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 . +// + +// +//! J-Head hot ends from Brian Reifsnider, hotends.com. +// +include <../core.scad> +include +include +include +include + +use +use <../utils/tube.scad> + +MK4_heater = [ 12.76, 15.88, 8.22, (15.88 / 2 - 4.5), (12.76 / 2 - 0.5 - 2.5 / 2), (-15.88 / 2 + 5), 9.5, 3]; +MK5_heater = [ 12.76, 12.76, 8.22, (12.76 / 2 - 3.75), (12.76 / 2 - 0.5 - 2.5 / 2), (-12.76 / 2 + 4), 8, 2]; + +function heater_width(type) = type[0]; +function heater_length(type) = type[1]; +function heater_height(type) = type[2]; +function resistor_x(type) = type[3]; +function thermistor_y(type) = type[4]; +function nozzle_x(type) = type[5]; +function nozzle_cone(type) = type[6]; +function nozzle_cone_length(type) = type[7]; + +barrel_tap_dia = 5; + +barrel_dia = 6; +insulator_dia = 12; + +module heater_block(type, resistor, thermistor) { + h = heater_height(type); + + color("gold") { + render() difference() { + rotate([90, 0, 0]) + linear_extrude(height = heater_width(type), center = true) difference() { + square([heater_length(type), h], center = true); + + translate([resistor_x(type), 0]) + circle(resistor_hole(resistor) / 2); + } + + translate([-heater_length(type) / 2, thermistor_y(type), 0]) // hole for thermistor + rotate([0, 90, 0]) + cylinder(r = resistor_hole(thermistor) / 2, h = 2 * resistor_length(thermistor), center = true); + } + // + // nozzle + // + cone_length = nozzle_cone_length(type); + cone_end_r = 1 / 2; + cone_start_r = nozzle_cone(type) / 2; + straight = 1; + nozzle_r = 0.4 / 2; + translate_z(-h / 2) vflip() + rotate_extrude() + polygon([ + [nozzle_r, 0], + [cone_start_r, 0], + [cone_start_r, straight], + [cone_end_r, straight + cone_length], + [nozzle_r, straight + cone_length], + ]); + } +} + +module jhead_hot_end(type, filament) { + resistor = RIE1212UB5C5R6; + thermistor = Epcos; + heater = type == JHeadMk4 ? MK4_heater : MK5_heater; + + insulator_length = hot_end_insulator_length(type); + inset = hot_end_inset(type); + length = hot_end_total_length(type); + barrel_length = length - insulator_length; + vitamin(str("jhead_hot_end(", type[0], ", ", filament, "): Hot end ", hot_end_part(type), " ", filament, "mm")); + // + // insulator + // + translate_z(inset - insulator_length) + color(hot_end_insulator_colour(type)) rotate_extrude() + difference() { + chamfer = 2; + hull() { + translate([0, chamfer]) + square([hot_end_insulator_diameter(type) / 2, insulator_length - chamfer]); + + square([hot_end_insulator_diameter(type) / 2 - chamfer, insulator_length]); + } + square([3.2 / 2, insulator_length]); + + translate([hot_end_groove_dia(type) / 2, insulator_length - hot_end_inset(type) - hot_end_groove(type)]) + square([100, hot_end_groove(type)]); + } + // + // heater block + // + rotate(90) + translate([-nozzle_x(heater), 0, inset - insulator_length - heater_height(heater) / 2]) + heater_block(heater, resistor, thermistor); +} + +module jhead_hot_end_assembly(type, filament, naked = false) { //! Assembly with resistor, thermistor, tape, sleaving and ziptie + resistor = RIE1212UB5C5R6; + thermistor = Epcos; + heater = type == JHeadMk4 ? MK4_heater : MK5_heater; + + insulator_length = hot_end_insulator_length(type); + inset = hot_end_inset(type); + length = hot_end_total_length(type); + barrel_length = length - insulator_length; + bundle = 3.2; + tape_width = 25; + tape_overlap = 10; + tape_thickness = 0.8; + + jhead_hot_end(type, filament); + + vitamin(": Tape self amalgamating silicone 110mm x 25mm"); + // + // silcone tape + // + if(!naked) + color("red") + if(exploded()) + translate([0, max(hot_end_insulator_diameter(type) / 2, heater_length(heater) / 2 - nozzle_x(heater)), + -tape_width + tape_overlap + inset - insulator_length]) + cube([110, tape_thickness, tape_width]); + else + hull() { + translate_z(+ inset - insulator_length) + cylinder(r = hot_end_insulator_diameter(type) / 2 + 2 * tape_thickness, h = tape_overlap); + + translate([0, -nozzle_x(heater), inset - insulator_length - heater_height(heater) / 2 + eps]) + cube([heater_width(heater) + 4 * tape_thickness, + heater_length(heater) + 4 * tape_thickness, heater_height(heater)], center = true); + } + // + // Zip tie and heatshrink + // + if(!naked) + rotate(10) { + dia = hot_end_insulator_diameter(type); + scale([1, (bundle + dia) / dia]) + translate([0, -bundle / 2, -7]) + rotate(-110) + ziptie(small_ziptie, dia / 2); + + translate([0, -dia / 2 - bundle / 2, 20]) + scale([0.7, bundle / 6.4]) + difference() { + tubing(HSHRNK64, 60); + if(!exploded()) + translate_z(20) + cube([10, 10, 60], center = true); + } + + } + wire("Red PTFE", 16, 170); + wire("Red PTFE", 16, 170); + // + // heater block + // + rotate(90) + translate([-nozzle_x(heater), 0, inset - insulator_length - heater_height(heater) / 2]) { + intersection() { + group() { + translate([resistor_x(heater), -exploded() * 15, 0]) + rotate([90, 0, 0]) + sleeved_resistor(resistor, PTFE20, bare = -10); + + translate([-heater_length(heater) / 2 + resistor_length(thermistor) / 2 - exploded() * 10, thermistor_y(heater), 0]) + rotate([90, 0, -90]) + sleeved_resistor(thermistor, PTFE07, heatshrink = HSHRNK16); + } + if(!exploded()) + if(naked) + color("grey") cylinder(r = 12, h = 100, center = true); + else + cube(1, true); // hide the wires when not exploded + } + } +} diff --git a/vitamins/leadnut.scad b/vitamins/leadnut.scad new file mode 100644 index 0000000..56b570b --- /dev/null +++ b/vitamins/leadnut.scad @@ -0,0 +1,67 @@ +// +// 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 . +// + +// +//! Nuts for leadscrews. +// +include <../core.scad> +include <../utils/tube.scad> + +function leadnut_bore(type) = type[2]; //! Thread size +function leadnut_od(type) = type[3]; //! Outer diameter of the shank +function leadnut_height(type) = type[4]; //! Total height +function leadnut_flange_dia(type) = type[5]; //! Flange diameter +function leadnut_flange_t(type) = type[6]; //! Flange thickness +function leadnut_flange_offset(type) = type[7]; //! Offset of the flange from the top +function leadnut_holes(type) = type[8]; //! The number of screw holes +function leadnut_hole_dia(type) = type[9]; //! The diameter of the screw holes +function leadnut_hole_pitch(type) = type[10]; //! The radia pitch of the screw holes +function leadnut_screw(type) = type[11]; //! The type of the fixing screws + +function leadnut_shank(type) = leadnut_height(type) - leadnut_flange_t(type) - leadnut_flange_offset(type); //! The length of the shank below the flange + +module leadnut_screw_positions(type) { //! Position children at the screw holes + holes = leadnut_holes(type); + for(i = [0 : holes - 1], a = i * 360 / holes + 180) + rotate(a) + translate([leadnut_hole_pitch(type), 0, leadnut_flange_t(type)]) + rotate(45) + children(); +} + +module leadnut(type) { //! Draw specified leadnut + vitamin(str("leadnut(", type[0], "): ", type[1])); + bore_r = (leadnut_bore(type) + 0.5) / 2; + + color("dimgrey") vflip() + translate_z(-leadnut_flange_offset(type) - leadnut_flange_t(type)) { + tube(or = leadnut_od(type) / 2, ir = bore_r, h = leadnut_height(type), center = false); + + translate_z(leadnut_flange_offset(type)) + linear_extrude(height = leadnut_flange_t(type)) + difference() { + circle(d = leadnut_flange_dia(type)); + + circle(bore_r); + + leadnut_screw_positions(type) + circle(d = leadnut_hole_dia(type)); + } + } +} diff --git a/vitamins/leadnuts.scad b/vitamins/leadnuts.scad new file mode 100644 index 0000000..e119cc2 --- /dev/null +++ b/vitamins/leadnuts.scad @@ -0,0 +1,25 @@ +// +// 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 . +// + +LSN8x2 = ["LSN8x2", "Leadscrew nut 8 x 2", 8, 10.2, 15, 22, 3.5, 1.5, 4, 3.5, 8, M3_cap_screw]; +LSN8x8 = ["LSN8x8", "Leadscrew nut 8 x 8 RobotDigg",8, 12.75,19, 25.4, 4.1, 0, 3, 3.5, 19.05/2, M3_cap_screw]; + +leadnuts = [LSN8x2, LSN8x8]; + +use diff --git a/vitamins/led.scad b/vitamins/led.scad new file mode 100644 index 0000000..59ed0c2 --- /dev/null +++ b/vitamins/led.scad @@ -0,0 +1,56 @@ +// +// 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 . +// + +// +//! Standard domed through hole LEDs. Can specify colour and lead length. +// +include <../core.scad> +use <../utils/rounded_cylinder.scad> + +function led_diameter(type) = type[1]; //! Body diameter +function led_rim_dia(type) = type[2]; //! Rim diameter +function led_rim_t(type) = type[3]; //! Rim height +function led_height(type) = type[4]; //! Body height +function led_pitch(type) = type[5]; //! Lead pitch +function led_lead_t(type) = type[6]; //! Lead thickness + +function led_hole_radius(type) = led_diameter(type) / 2; //! Radius of panel hole to accept LED + +module led(type, colour = "red", lead = 5) { //! Draw specified LED with desired colour and led length + d = led_diameter(type); + vitamin(str("led(", type[0], arg(colour, "red"), "): LED ", d, " mm ", colour)); + + color(colour) { + rotate_extrude() + rounded_corner(r = d / 2, h = led_height(type), r2 = d / 2); + + linear_extrude(height = led_rim_t(type)) + difference() { + circle(d = led_rim_dia(type)); + + translate([d / 2 + eps, -5]) + square(10); + } + } + color("silver") + for(side = [-1, 1], len = lead - side) + translate([side * led_pitch(type) / 2, 0, -len / 2]) + vflip() + cube([led_lead_t(type), led_lead_t(type), len], center = true); +} diff --git a/vitamins/leds.scad b/vitamins/leds.scad new file mode 100644 index 0000000..4da2f26 --- /dev/null +++ b/vitamins/leds.scad @@ -0,0 +1,34 @@ +// +// 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 . +// + +// +// d r r h p l +// i i i e i e +// a m m i t a +// g c d +// d t h h +// t t +// +LED3mm = ["LED3mm", 3, 3.1, 1.0, 4.5, 2.54, 0.4]; +LED5mm = ["LED5mm", 5, 5.6, 0.9, 8.5, 2.54, 0.4]; +LED10mm = ["LED10mm", 10, 11.0, 2.0, 13.5, 2.54, 0.4]; + +LEDs = [LED3mm, LED5mm, LED10mm]; + +use diff --git a/vitamins/light_strip.scad b/vitamins/light_strip.scad new file mode 100644 index 0000000..9770bac --- /dev/null +++ b/vitamins/light_strip.scad @@ -0,0 +1,166 @@ +// +// 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 . +// + +// +//! LED strip lights that can be cut to size. +//! +//! The definitions are for the full length but they can be cut to size by specifying how many segments, +//! which can by calcuated using ```light_strip_segments(type, max_length)```. +//! +//! The `light_strip_clip()` module makes a clip to go around the light that can be incorporated into a printed bracket to hold it. +// +include <../core.scad> + +function light_strip_length(type) = type[2]; //! Un-cut length +function light_strip_leds(type) = type[3]; //! Total number of LEDs +function light_strip_grouped(type) = type[4]; //! Number of LEDs in each group +function light_strip_width(type) = type[5]; //! Outside width +function light_strip_depth(type) = type[6]; //! Outside depth +function light_strip_aperture(type) = type[7]; //! Inside width +function light_strip_thickness(type) = type[8]; //! Metal thickness +function light_strip_pcb_thickness(type) = type[9]; //! PCB thickness + +function light_strip_segments(type, max_length) = let( //! Calculate the maximum number of segments that fit in max_length + length = light_strip_length(type), + seg_length = length * light_strip_grouped(type) / light_strip_leds(type), + segs = floor(min(max_length, length) / seg_length) + ) + assert(segs, str("max_length must be at least ", ceil(seg_length), "mm")) + segs; + +function light_strip_cut_length(type, segs) = ceil(light_strip_length(type) * segs * light_strip_grouped(type) / light_strip_leds(type)); //! Calculate cut length given segments + +module light_strip(type, segs = undef) { //! Draw specified light strip, segs can be used to limit the length + segment_length = light_strip_length(type) / (light_strip_leds(type) / light_strip_grouped(type)); + segments = is_undef(segs) ? leds / light_strip_grouped(type) : segs; + l = light_strip_cut_length(type, segs); + vitamin(str("light_strip(", type[0], arg(segs, undef), "): Light strip ", type[1], " x ", l, "mm (", segments, " segments)")); + leds = light_strip_grouped(type) * segments; + w = light_strip_width(type); + d = light_strip_depth(type); + t = light_strip_thickness(type); + a = light_strip_aperture(type); + s = (w - a) / 2 - t; + p = light_strip_pcb_thickness(type); + x1 = w / 2; + x2 = x1 - t; + x3 = a / 2; + y1 = t; + y5 = d - s; + y4 = y5 - t; + y3 = y4 - p; + y2 = y3 - t; + + module led_positions() + for(i = [0 : leds - 1]) + translate([l * (i + 0.5) / leds - l / 2, 0]) + children(); + + module segment_positions(n = segments) + for(i = [0 : 1 : n - 1]) + translate([l * i / segments - l / 2, 0]) + children(); + + module resistor_positions() + segment_positions() + for(end = [-1, 1], side = end > 0 ? [-1, 1] : [0]) + translate([end * l / leds / 2 + segment_length / 2, side * 2]) + children(); + + color("silver") + rotate([90, 0, 90]) + linear_extrude(height = l, center = true) + polygon([ + [ x1, 0], [ x1, d], [ x2, d], [ x3, y5], [ x3, y4], [ x2, y4], + [ x2, y3], [ x3, y3], [ x3, y2], [ x2, y2], [ x2, y1], + [-x2, y1], [-x2, y2], [-x3, y2], [-x3, y3], [-x2, y3], [-x2, y4], + [-x3, y4], [-x3, y5], [-x2, d], [-x1, d], [-x1, 0], + ]); + + color("ghostwhite") + translate_z(y3 + p / 2) + cube([l, w - 2 * t, p], center = true); + + translate_z(y4) { + color("white") + linear_extrude(height = 1.6) + led_positions() + square([5, 5], center = true); + + color("yellow") + linear_extrude(height = 1.6 + eps) + led_positions() + circle(d = 3.5); + + color("silver") + linear_extrude(height = 0.8) + led_positions() + for(side = [-1,1], end = [-1:1]) + translate([side * 2.2, end * 1.6]) + square([1, 0.9], center = true); + + color("black") + linear_extrude(height = 0.1) + segment_positions(segments - 1) + translate([segment_length, 0]) + square([0.2, a], center = true); + + color("silver") + linear_extrude(height = 0.15) + segment_positions() + for(end = [-1, 1], side = [-1, 1]) + translate([end * (segment_length / 2 - 1.25) + segment_length / 2, side * 2.5]) + square(2.5, center = true); + + color("silver") + linear_extrude(height = 0.55) + resistor_positions() + square([3.2, 1.5], center = true); + + color("black") + linear_extrude(height = 0.55 + eps) + resistor_positions() + square([2.1, 1.5 + 2 * eps], center = true); + + } + + if(show_rays) + %cylinder(r = 1, h = 150); +} + +wall = 1.8; +clearance = 0.2; +function light_strip_clip_slot(light) = light_strip_width(light) + clearance; //! Clip slot size +function light_strip_clip_depth(light) = 10; //! Depth of the clip +function light_strip_clip_length(light) = light_strip_clip_slot(light) + 2 * wall; //! Outside length +function light_strip_clip_width(light) = light_strip_depth(light) + 2 * wall; //! Outside width + +module light_strip_clip(light) { //! Make a clip to go over the strip to be incorporated into a bracket + linear_extrude(height = light_strip_clip_depth(light), convexity = 2) + difference() { + translate([-light_strip_clip_length(light) / 2, -wall]) + square([light_strip_clip_length(light), light_strip_clip_width(light)]); + + translate([-light_strip_clip_slot(light) / 2, 0]) + square([light_strip_clip_slot(light), light_strip_clip_width(light) - 2 * wall]); + + translate([-light_strip_aperture(light) / 2, 0]) + square([light_strip_aperture(light), 100]); + } +} diff --git a/vitamins/light_strips.scad b/vitamins/light_strips.scad new file mode 100644 index 0000000..696349f --- /dev/null +++ b/vitamins/light_strips.scad @@ -0,0 +1,33 @@ +// +// 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 . +// +// l l g w d a t p +// e e r i e p h c +// n d o d p e i b +// g s u t t r c +// t p h h t k t +// h u n h +// r e i +// e s c +// s k +Rigid5050 = ["Rigid5050", "rigid SMD5050 low profile", 500, 36, 3, 14.4, 7, 10.4, 0.9, 1.2]; +RIGID5050 = ["RIGID5050", "rigid SMD5050" , 500, 36, 3, 14.4, 8.6, 10.4, 0.9, 1.6]; + +light_strips = [Rigid5050, RIGID5050,]; + +use diff --git a/vitamins/linear_bearing.scad b/vitamins/linear_bearing.scad new file mode 100644 index 0000000..1cc699b --- /dev/null +++ b/vitamins/linear_bearing.scad @@ -0,0 +1,44 @@ +// +// 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 . +// + +// +//! LMnUU linear bearings. +// +include <../core.scad> + +use <../utils/tube.scad> + +bearing_colour = grey70; +seal_colour = grey20; + +function bearing_length(type) = type[1]; //! Total length +function bearing_dia(type) = type[2]; //! Outside diameter +function bearing_rod_dia(type) = type[3]; //! Internal diameter + +function bearing_radius(type) = bearing_dia(type) / 2; //! Outside radius + +module linear_bearing(type) { //! Draw specified linear bearing + vitamin(str("linear_bearing(", type[0], "): Linear bearing LM", bearing_rod_dia(type),"UU")); + + casing_t = bearing_radius(type) / 10; + casing_ir = bearing_radius(type) - casing_t; + + color(bearing_colour) tube(or = bearing_radius(type), ir = casing_ir, h = bearing_length(type)); + color(seal_colour) tube(or = casing_ir, ir = bearing_rod_dia(type) / 2, h = bearing_length(type) - 0.5); +} diff --git a/vitamins/linear_bearings.scad b/vitamins/linear_bearings.scad new file mode 100644 index 0000000..0600601 --- /dev/null +++ b/vitamins/linear_bearings.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +// Linear bearings +// +LM12UU = ["LM12UU", 30, 21, 12]; +LM10UU = ["LM10UU", 29, 19, 10]; +LM8UU = ["LM8UU", 24, 15, 8]; +LM6UU = ["LM6UU", 19, 12, 6]; +LM5UU = ["LM5UU", 15, 10, 5]; +LM4UU = ["LM4UU", 12, 8, 4]; +LM3UU = ["LM3UU", 10, 7, 3]; + +linear_bearings = [LM3UU, LM4UU, LM5UU, LM6UU, LM8UU, LM10UU, LM12UU]; + +use diff --git a/vitamins/mains_socket.scad b/vitamins/mains_socket.scad new file mode 100644 index 0000000..e7dc2ac --- /dev/null +++ b/vitamins/mains_socket.scad @@ -0,0 +1,123 @@ +// +// 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 . +// + +// +//! UK 13A sockets at the moment. +// +include <../core.scad> +include +include +include + +function mains_socket_width(type) = type[1]; //! Width at the base +function mains_socket_depth(type) = type[2]; //! Depth at the base +function mains_socket_top_w(type) = type[3]; //! Width at the top, might be tapered +function mains_socket_top_d(type) = type[4]; //! Depth at the top, might be tapered +function mains_socket_corner(type) = type[5]; //! Corner radius +function mains_socket_height(type) = type[6]; //! Height +function mains_socket_t(type) = type[7]; //! Plastic thickness +function mains_socket_offset(type) = type[8]; //! Offset of the socket from the centre +function mains_socket_pitch(type) = type[9]; //! Screw hole pitch +function mains_socket_screw(type) = M3_cs_cap_screw; //! Screw type + +earth = M3_ringterm; +earth_screw = ringterm_screw(earth); +insert_wall = 3; + +function mains_socket_insert_boss(type) = 2 * (insert_hole_radius(screw_insert(mains_socket_screw(type))) + insert_wall); + +module face_plate(type) + rounded_square([mains_socket_width(type), mains_socket_depth(type)], mains_socket_corner(type)); + +module mains_socket_hole_positions(type) //! Position children at the screw holes + for(side = [-1, 1]) + translate([side * mains_socket_pitch(type) / 2, 0]) + children(); + +module mains_socket_earth_position(type) { //! Position of earth terminal for DiBond panel + inset = mains_socket_t(type) + washer_diameter(screw_washer(earth_screw)) / 2 + 1; + + translate([-mains_socket_width(type) / 2 + inset, -mains_socket_depth(type) / 2 + inset]) + children(); +} + +module mains_socket_holes(type, h = 0) { //! Panel cutout + mains_socket_hole_positions(type) + drill(screw_clearance_radius(mains_socket_screw(type)), h); + + extrude_if(h) + offset(cnc_bit_r) offset(-cnc_bit_r) difference() { + offset(-7) face_plate(type); + + for(side = [-1, 1]) + hull() + for(x = [1, 2]) + translate([side * mains_socket_pitch(type) / x, 0]) + circle(4.5); + + mains_socket_earth_position(type) + circle(d = washer_diameter(screw_washer(earth_screw)) + 2); + } + + mains_socket_earth_position(type) + drill(screw_clearance_radius(earth_screw), h); +} + +module mains_socket(type) { //! Draw specified 13A socket + offset = mains_socket_offset(type); + screw = mains_socket_screw(type); + height = mains_socket_height(type); + + vitamin(str("mains_socket(", type[0], "): Mains socket 13A", offset.x || offset.y ? ", switched" : "")); + + color("white") render() difference() { + hull() { + linear_extrude(height = eps) + face_plate(type); + + linear_extrude(height = height) + offset(-(mains_socket_width(type) - mains_socket_top_w(type)) / 2) + face_plate(type); + } + // Holes for pins + translate([offset.x, offset.y, mains_socket_height(type)]) { + for(side = [-1, 1]) + translate([side * 11.1, -11.1]) + cube([7, 4.5, 8], center = true); + + translate([0, 11.1]) + cube([4.5, 8.5, 8], center = true); + } + // Hollow out the back + difference() { + linear_extrude(height = height - mains_socket_t(type)) + offset(-mains_socket_t(type)) + face_plate(type); + + cube(50, center = true); + } + // Screw holes + mains_socket_hole_positions(type) { + cylinder(r = screw_clearance_radius(screw), h = 100, center = true); + + translate_z(height) + screw_countersink(screw); + } + } +} diff --git a/vitamins/mains_sockets.scad b/vitamins/mains_sockets.scad new file mode 100644 index 0000000..07250a5 --- /dev/null +++ b/vitamins/mains_sockets.scad @@ -0,0 +1,29 @@ +// +// 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 . +// + +// +//! UK 13A sockets at the moment. +// + +MKLOGIC = ["MKLOGIC", 86, 86, 86, 86, 3.6, 9, 3.6, [-9, -9], 60.3]; // Screwfix, switched +Contactum = ["Contactum", 84, 84, 80, 80, 4.0, 10.5, 3.6, [ 0, 0], 60.3]; // Old and unswitched + +mains_sockets = [MKLOGIC, Contactum]; + +use diff --git a/vitamins/meter.scad b/vitamins/meter.scad new file mode 100644 index 0000000..ba6f4fe --- /dev/null +++ b/vitamins/meter.scad @@ -0,0 +1,130 @@ +// +// 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 . +// + +// +//! LED volt meter modules available from China and a printed bezel that allows them to be mounted into a +//! CNC cut panel. The meter is held in the bezel by melting the stakes with a soldering iron set to 200°C. The +//! bezel is fixed in the panel with hot glue. +//! +//! Needs 7 segment font from to look realistic. +// +include <../core.scad> + +led_meter = ["led_meter", 22.72, 10.14, 6.3, 22.72, 11.04, 0.96, 30, 4.2, 26, 2.2 / 2]; + +function meter() = led_meter; //! Default meter type + +function meter_length(type = led_meter) = type[1]; //! Length of body +function meter_width(type = led_meter) = type[2]; //! Width of body +function meter_height(type = led_meter) = type[3]; //! Height of body excluding PCB +function meter_pcb_length(type = led_meter) = type[4]; //! PCB length excluding lugs +function meter_pcb_width(type = led_meter) = type[5]; //! PCB width +function meter_pcb_thickness(type = led_meter) = type[6]; //! PCB thickness +function meter_lug_length(type = led_meter) = type[7]; //! PCB length including lugs +function meter_lug_width(type = led_meter) = type[8]; //! Lug width +function meter_hole_pitch(type = led_meter) = type[9]; //! Lug hole pitch +function meter_hole_radius(type = led_meter) = type[10]; //! Lug hole radius + +module meter_hole_positions(type = led_meter) //! Position children over the holes + for(side = [-1, 1]) + translate([side * meter_hole_pitch(type) / 2, 0]) + children(); + +module meter(type = led_meter, colour = "red", value = "888", display_colour = false) //! Draw a meter with optional colour and display value +{ + vitamin(str("meter(", type[0], arg(colour, "red", "colour"), "): LED meter ", colour)); + + color("grey") + translate_z(meter_height(type) / 2) + cube([meter_length(type), meter_width(type), meter_height(type)], center = true); + + color("green") + translate_z(meter_height(type)) + linear_extrude(height = meter_pcb_thickness(type)) + difference() { + union() { + square([meter_pcb_length(type), meter_pcb_width(type)], center = true); + + square([meter_lug_length(type), meter_lug_width(type)], center = true); + } + meter_hole_positions(type) + circle(meter_hole_radius(type)); + } + + color(display_colour ? display_colour : colour) + linear_extrude(height = 0.2, center = true) + mirror([1,0,0]) + text(value, font = "7 segment", valign = "center", halign = "center", size = meter_width(type) - 2, spacing = 1.2); +} + +clearance = 0.1; +overlap = 1; +flange_t = 1; + +function meter_bezel_wall(type = led_meter) = (meter_lug_length(type) - meter_length(type)) / 2; //! Printed bezel wall thickness +function meter_bezel_rad(type = led_meter) = meter_bezel_wall(type); //! Printed bezel corner radius +function meter_bezel_length(type = led_meter) = meter_length(type) + 2 * (meter_bezel_wall(type) + overlap); //! Printed bezel length +function meter_bezel_width(type = led_meter) = meter_width(type) + 2 * (meter_bezel_wall(type) + overlap); //! Printed bezel width + +module meter_bezel_hole(type = led_meter, h = 100) { //! Make a hole to fit the meter Bezel + wall = meter_bezel_wall(type) + clearance; + rad = meter_bezel_rad(type) + clearance; + l = meter_length(type); + w = meter_width(type); + + extrude_if(h) + rounded_square([l + 2 * wall, w + 2 * wall], rad); +} + +module meter_bezel(type = led_meter) { //! Generate the STL for the meter bezel + stl("meter_bezel"); + + wall = meter_bezel_wall(type); + rad = meter_bezel_rad(type); + l = meter_length(type); + w = meter_width(type); + h = meter_height(type); + + union() { + linear_extrude(height = h) + difference() { + rounded_square([l + 2 * wall, w + 2 * wall], rad); + + square([l + 2 * clearance, w + 2 * clearance], center = true); + } + + linear_extrude(height = flange_t) + difference() { + rounded_square([l + 2 * wall + 2 * overlap, w + 2 * wall + 2 * overlap], rad + overlap); + + square([l + 2 * clearance, w + 2 * clearance], center = true); + } + meter_hole_positions(type) + cylinder(r = meter_hole_radius(type), h = h + meter_pcb_thickness(type) * 2); + } +} + +module meter_assembly(type = led_meter, colour = "red", value = "888", display_colour = false) { //! Meter assembled into the bezel + vflip() + translate_z(-flange_t) { + color("dimgrey") meter_bezel(type); + + meter(type, colour, value, display_colour); + } +} diff --git a/vitamins/microswitch.scad b/vitamins/microswitch.scad new file mode 100644 index 0000000..53bbb6e --- /dev/null +++ b/vitamins/microswitch.scad @@ -0,0 +1,117 @@ +// +// 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 . +// + +// +//! Used for limit switches. +// +include <../core.scad> + +microswitch_contact_color = "gold"; + +function microswitch_thickness(type) = type[2]; //! Body thickness +function microswitch_width(type) = type[3]; //! Body width +function microswitch_length(type) = type[4]; //! Body length +function microswitch_radius(type) = type[5]; //! Body corner radius +function microswitch_hole_d(type) = type[6]; //! Screw hole diameter +function microswitch_holes(type) = type[7]; //! Hole positions +function microswitch_button_w(type) = type[8]; //! Button width +function microswitch_button_t(type) = type[9]; //! Button thickness +function microswitch_button_pos(type)= type[10]; //! Button position +function microswitch_legs(type) = type[11]; //! Leg positions +function microswitch_leg(type) = type[12]; //! Leg types +function microswitch_body_clr(type) = type[13]; //! Body colour +function microswitch_button_clr(type)= type[14]; //! Button colour + +function microswitch_lower_extent(type) = let(leg = microswitch_leg(type)) min([for(pos = microswitch_legs(type)) pos.y - leg.y / 2]); //! How far legs extend downwards +function microswitch_right_extent(type) = let(leg = microswitch_leg(type)) max([microswitch_length(type) / 2, for(pos = microswitch_legs(type)) pos.x + leg.x / 2]); //! How far legs extend right + +module microswitch_hole_positions(type) //! Place children at the hole positions +{ + for(hole = microswitch_holes(type)) + translate(hole) + children(); +} + +module microswitch_wire_positions(type, skip = undef) { //! Place children at the leg hole positions + leg = microswitch_leg(type); + legs = microswitch_legs(type); + for(i = [0 : len(legs) - 1]) + if(i != skip) + let(pos = legs[i]) + translate(leg[3] ? pos + leg[4] : pos - [leg.x, leg.y] / 6) + children(); +} + +module microswitch(type) { //! Draw specified microswitch + vitamin(str("microswitch(", type[0], "): Microswitch ", type[1])); + d = microswitch_button_t(type); + + color(microswitch_body_clr(type)) + linear_extrude(height = microswitch_thickness(type), center = true) + difference() { // main body + rounded_square([microswitch_length(type), microswitch_width(type)], microswitch_radius(type)); + + microswitch_hole_positions(type) + circle(d = microswitch_hole_d(type)); + } + + color(microswitch_button_clr(type)) // orange button + translate(microswitch_button_pos(type) - [0, d / 2]) + linear_extrude(height = microswitch_button_w(type), center = true) + hull() { + circle(d = d); + + translate([0, -3]) + circle(d = d); + } + + color(microswitch_contact_color) // yellow contacts + for(pos = microswitch_legs(type)) + translate(pos) { + leg = microswitch_leg(type); + vertical = leg.y > leg.x; + + if(vertical) + rotate([0, 90, 0]) + linear_extrude(height = leg.x, center = true) + difference() { + square([leg.z, leg.y], center = true); + + if(leg[3]) + translate(leg[4]) + circle(d = leg[3]); + } + else + rotate([90, 0, 0]) + linear_extrude(height = leg.y, center = true) + difference() { + square([leg.x, leg.z], center = true); + + if(leg[3]) + translate(leg[4]) + circle(d = leg[3]); + } + + if(!vertical && pos.y < -microswitch_width(type) / 2) { + gap = -microswitch_width(type) / 2 - pos.y; + translate([-leg.x / 2 + leg.y / 2, gap / 2]) + cube([leg.y, gap, leg.z], center = true); + } + } +} diff --git a/vitamins/microswitches.scad b/vitamins/microswitches.scad new file mode 100644 index 0000000..58f2351 --- /dev/null +++ b/vitamins/microswitches.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +// Microswitches +// +small_leg = [0.9, 3.3, 0.4, 0]; +medium_leg = [0.5, 3.9, 3.2, 1.6, [0, -0.5]]; +large_leg = [11.4, 0.8, 6.3, 1.8, [1.7, 0]]; + +small_microswitch = ["small_microswitch", "DM1-00P-110-3", 5.8, 6.5, 12.8, 0, 2, [[-3.25, -1.65], [3.25, -1.65]], 2.9, 1.2, [-1.95, 3.75], [[-5.08, -4.95], [0, -4.9], [5.08, -4.9] ], small_leg, grey20, "white" ]; +medium_microswitch = ["medium_microswitch","SS-01 or SS-5GL", 6.4, 10.2, 19.8, 1, 2.35, [[-4.8, -2.6 ], [4.7, -2.6 ]], 3.2, 2, [-2.8, 5.8 ], [[-8.05, -7.05], [0.75, -7.05], [8.05, -7.05] ], medium_leg, grey20, "burlywood" ]; +large_microswitch = ["large_microswitch", "Saia G3 low force", 10.4, 15.9, 28.0, 2, 3.1, [[-11.1, -5.15], [11.2, 5.15]], 4, 2.75,[-9.1, 9.55], [[19.7, 2.19], [19.7, -3.45], [8.3, -10.45] ], large_leg, "ivory", "white" ]; + +microswitches = [small_microswitch, medium_microswitch, large_microswitch]; + +use diff --git a/vitamins/microview.scad b/vitamins/microview.scad new file mode 100644 index 0000000..f33c736 --- /dev/null +++ b/vitamins/microview.scad @@ -0,0 +1,59 @@ +// +// 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 . +// + +// +//! Microview OLED display with on board AVR by geekammo / Sparkfun. +//! +//! ```microview()``` generates the model. ```microview(true)``` makes an object to cut out a panel aperture for it. +//! +//! Uses STL files copyright geekammo and licenced with MIT license, see [microview/LICENSE.txt](vitamins/microview/LICENSE.txt). +// +include <../core.scad> +use // for pin + +panel_clearance = 0.2; + +module microview(cutout = false) { //! Draw microview or generate a panel cutout for it + rotate([0, 0, -90]) + if(cutout) + linear_extrude(height = 100) + offset(panel_clearance) + projection() + hull() + import("microview/GKM-003_R05_CHIP_LOWER_HOUSING.stl"); + else { + vitamin("microview(): Microview OLED display"); + + translate_z(8.35) { + + color("black") + import("microview/GKM-002_R05_CHIP_UPPER_HOUSING-1.stl", convexity = 2); + + translate([-2, 0, 0]) + color("dimgray") + cube([12.5, 15.5, 4.41], center = true); + } + color("dimgray") + import("microview/GKM-003_R05_CHIP_LOWER_HOUSING.stl", convexity = 2); + + for(side = [-1, 1], i = [0 : 7]) + translate([side * inch(0.35), (i - 3.5) * inch(0.1)]) + pin(); + } +} diff --git a/vitamins/microview/GKM-002_R05_CHIP_UPPER_HOUSING-1.STL b/vitamins/microview/GKM-002_R05_CHIP_UPPER_HOUSING-1.STL new file mode 100644 index 0000000..ed64b93 Binary files /dev/null and b/vitamins/microview/GKM-002_R05_CHIP_UPPER_HOUSING-1.STL differ diff --git a/vitamins/microview/GKM-003_R05_CHIP_LOWER_HOUSING.STL b/vitamins/microview/GKM-003_R05_CHIP_LOWER_HOUSING.STL new file mode 100644 index 0000000..e7524c1 Binary files /dev/null and b/vitamins/microview/GKM-003_R05_CHIP_LOWER_HOUSING.STL differ diff --git a/vitamins/microview/LICENSE.txt b/vitamins/microview/LICENSE.txt new file mode 100644 index 0000000..d6e0a5b --- /dev/null +++ b/vitamins/microview/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 geekammo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vitamins/module.scad b/vitamins/module.scad new file mode 100644 index 0000000..c3e4470 --- /dev/null +++ b/vitamins/module.scad @@ -0,0 +1,147 @@ +// +// 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 . +// + +// +//! Random screw down modules. Currently just DROK buck converters. +// +include <../core.scad> +include + +function mod_part(type) = type[1]; //! Description +function mod_length(type) = type[2]; //! Body length +function mod_width(type) = type[3]; //! Body width +function mod_height(type) = type[4]; //! Body height +function mod_screw(type) = type[5]; //! Screw type +function mod_screw_z(type)= type[6]; //! Thickness of screw lug +function mod_hole_r(type) = type[7] / 2; //! Screw hole radius +function mod_holes(type) = type[8]; //! Screw hole positions + +module mod(type) { //! Draw specified module + vitamin(str("mod(", type[0], "): ", mod_part(type))); + + module drok_buck() { + l = mod_length(type); + w = mod_width(type); + h = mod_height(type); + body_l = 31; + end_t = 1.5; + chamfer = 2; + lug_l = (l - body_l) / 2 - end_t; + lug_w = 19; + lug_w2 = 10; + lug_t = 2; + lug_r = 2.5; + hole_r = mod_hole_r(type); + vane_t = 1; + vane_h = 5; + vane_l = 7; + vane_p = 10; + boss_od = 7.5; + boss_id = 5; + boss_h = 2.3; + boss_chamfer = 1; + + + module profile() + hull() { + translate([-w / 2, 0]) + square([w, h - chamfer]); + + translate([-w / 2 + chamfer, 0]) + square([w - 2 * chamfer, h]); + } + + module lug() + difference() { + hull() { + for(side = [-1, 1]) + translate([side * lug_w2 / 2, lug_l - lug_r]) + circle(lug_r); + + translate([-lug_w / 2, -1]) + square([lug_w, 1]); + } + hull() + for(y = [hole_r, 100]) + translate([0, y]) + circle(hole_r); + } + + color("silver") + rotate([90, 0, 90]) + linear_extrude(height = body_l, center = true) + profile(); + + color(grey20) + for(end = [-1, 1]) + translate([end * body_l / 2, 0, 0]) + rotate([90, 0, end * 90]) + union() { + linear_extrude(height = end_t) // endcap + profile(); + + translate_z(end_t) + rotate([90, 0, 180]) + linear_extrude(height = lug_t) // lug + lug(); + + for(side = [-1, 1]) { + translate([side * vane_p / 2, lug_t, end_t]) // buttress vanes + rotate([0, -90, 0]) + linear_extrude(height = vane_t, center = true) + polygon([[0, 0], [0, vane_h - lug_t], [vane_l, 0]]); + + translate([side * vane_p / 2, h / 2, end_t]) // bosses + rotate_extrude() + difference() { + hull() { + square([boss_od / 2,boss_h - boss_chamfer]); + square([boss_od / 2 - boss_chamfer, boss_h]); + } + translate([0, boss_h - boss_chamfer]) + square([boss_id / 2, boss_h]); + } + } + } + } + drok_buck(); +} + +module mod_screw_positions(type) //! Position children at the screw positions + for(p = mod_holes(type)) + translate([p.x, p.y]) + children(); + +module module_assembly(type, thickness) { //! Module with its fasteners in place + screw = mod_screw(type); + washer = screw_washer(screw); + nut = screw_nut(screw); + screw_length = screw_longer_than(thickness + mod_screw_z(type) + 2 * washer_thickness(washer) + nut_thickness(nut, true)); + + mod(type); + + mod_screw_positions(type) { + translate_z(mod_screw_z(type)) + nut_and_washer(nut, true); + + translate_z(-thickness) + vflip() + screw_and_washer(screw, screw_length); + } +} diff --git a/vitamins/modules.scad b/vitamins/modules.scad new file mode 100644 index 0000000..f7df40b --- /dev/null +++ b/vitamins/modules.scad @@ -0,0 +1,37 @@ +// +// 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 . +// + +// +// Random modules +// + +// +// p l w h s s h h +// a e i e c c o o +// r n d i r r l l +// t g t g e e e e +// h h h w w s +// t d +// z +// +drok_buck = ["drok_buck", "Drok buck converter", 50, 25, 20.5, M4_dome_screw, 2, 4, [[-21, 0], [21, 0]]]; + +modules = [drok_buck]; + +use diff --git a/vitamins/nut.scad b/vitamins/nut.scad new file mode 100644 index 0000000..16c7e0e --- /dev/null +++ b/vitamins/nut.scad @@ -0,0 +1,140 @@ +// +// 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 . +// + +// +//! Default is steel but can be drawn as brass or nylon. A utility for making nut traps included. +//! +//! If a nut is given a child then it gets placed on its top surface. +// +include <../core.scad> +use +use +use <../utils/rounded_cylinder.scad> + +function nut_size(type) = type[1]; //! Diameter of the corresponding screw +function nut_radius(type) = type[2] / 2; //! Radius across the corners +function nut_thickness(type, nyloc = false) = nyloc ? type[4] : type[3]; //! Thickness of plain or nyloc version +function nut_washer(type) = type[5]; //! Corresponding washer +function nut_trap_depth(type) = type[6]; //! Depth of nut trap + +function nut_flat_radius(type) = nut_radius(type) * cos(30); //! Radius across the flats + +module nut(type, nyloc = false, brass = false, nylon = false) { //! Draw specified nut + hole_rad = nut_size(type) / 2; + outer_rad = nut_radius(type); + thickness = nut_thickness(type); + nyloc_thickness = type[4]; + desc = nyloc ? "nyloc" : brass ? "brass" : nylon ? "nylon" : ""; + vitamin(str("nut(", type[0], arg(nyloc, false, "nyloc"), arg(brass, false, "brass"), arg(nylon, false, "nylon"), + "): Nut M", nut_size(type), " ", desc)); + + if(exploded() && nyloc) + cylinder(r = 0.2, h = 10); + + color(brass? brass : nylon ? grey30: grey70) translate_z((exploded() && nyloc) ? 10 : 0) { + linear_extrude(height = thickness) + difference() { + circle(outer_rad, $fn = 6); + + circle(hole_rad); + } + if(nyloc) + translate_z(-eps) + rounded_cylinder(r = outer_rad * cos(30) , h = nyloc_thickness, r2 = (nyloc_thickness - thickness) / 2, ir = hole_rad); + } + if($children) + translate_z(thickness) + children(); +} + +module nut_and_washer(type, nyloc) { //! Draw nut with corresponding washer + washer = nut_washer(type); + + translate_z(exploded() ? 7 : 0) + washer(washer); + + translate_z(washer_thickness(washer)) + nut(type, nyloc); +} + +module wingnut(type) { //! Draw a wingnut + hole_rad = nut_size(type) / 2; + bottom_rad = nut_radius(type); + top_rad = type[4] / 2; + thickness = nut_thickness(type); + wing_span = type[7]; + wing_height = type[8]; + wing_width = type[9]; + wing_thickness = type[10]; + + top_angle = asin((wing_thickness / 2) / top_rad); + bottom_angle = asin((wing_thickness / 2) / bottom_rad); + + vitamin(str("wingnut(", type[0], "): Wingnut M", nut_size(type))); + + explode(10) color(grey70) { + rotate_extrude() + polygon([ + [hole_rad, 0], + [bottom_rad, 0], + [top_rad,, thickness], + [hole_rad, thickness] + ]); + for(rot = [0, 180]) + rotate([90, 0, rot]) linear_extrude(height = wing_thickness, center = true) + hull() { + translate([wing_span / 2 - wing_width / 2, wing_height - wing_width / 2]) + circle(wing_width / 2); + polygon([ + [bottom_rad * cos(top_angle) - eps, 0], + [wing_span / 2 - wing_width / 2, wing_height - wing_width / 2], + [top_rad * cos(top_angle) - eps, thickness], + ]); + } + } +} +function nut_trap_radius(nut, horizontal = false) = nut_radius(nut) + (horizontal ? layer_height / 4 : 0); //! Radius across the corners of a nut trap +function nut_trap_flat_radius(nut, horizontal = false) = nut_trap_radius(nut, horizontal) * cos(30); //! Radius across the flats of a nut trap + +module nut_trap(screw, nut, depth = 0, horizontal = false, supported = false, h = 200) { //! Make a nut trap + nut_r = is_list(nut) ? nut_trap_radius(nut, horizontal) : nut + (horizontal ? layer_height / 4 : 0); + nut_d = depth ? depth : nut_trap_depth(nut); + screw_r = is_list(screw) ? screw_clearance_radius(screw) : screw; + render(convexity = 5) union() { + if(horizontal) { + if(screw_r) + teardrop_plus(r = screw_r, h = h); + + cylinder(r = nut_r, h = nut_d * 2, center = true, $fn = 6); + } + else { + difference() { + union() { + if(screw_r) + poly_cylinder(r = screw_r, h = h, center = true); + + cylinder(r = nut_r, h = nut_d * 2, center = true, $fn = 6); + } + if(supported) + translate_z(nut_d - eps) + cylinder(r = nut_r + eps, h = layer_height, center = false); + } + } + } +} diff --git a/vitamins/nuts.scad b/vitamins/nuts.scad new file mode 100644 index 0000000..6de2459 --- /dev/null +++ b/vitamins/nuts.scad @@ -0,0 +1,56 @@ +// +// 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 . +// + +// +// Nuts +// +M2_nut_trap_depth = 2.5; +M2p5_nut_trap_depth = 2.5; +M3_nut_trap_depth = 3; +M4_nut_trap_depth = 4; +M5_nut_depth = 4; +M6_nut_depth = 5; +M8_nut_depth = 6.5; + +// s r t n w t +// c a h y a r +// r d i l s a +// e i c o h p +// w u k c e +// s n r d +// e t e +// s h p +// s k t +// h +// +M2_nut = ["M2_nut", 2, 4.9, 1.6, 2.4, M2_washer, M2_nut_trap_depth]; +M2p5_nut = ["M2p5_nut", 2.5, 5.8, 2.2, 3.8, M2p5_washer, M2p5_nut_trap_depth]; +M3_nut = ["M3_nut", 3, 6.4, 2.4, 4, M3_washer, M3_nut_trap_depth]; +M4_nut = ["M4_nut", 4, 8.1, 3.2, 5, M4_washer, M4_nut_trap_depth]; +M5_nut = ["M5_nut", 5, 9.2, 4, 6.25, M5_washer, M5_nut_depth]; +M6_nut = ["M6_nut", 6, 11.5, 5, 8, M6_washer, M6_nut_depth]; +M6_half_nut = ["M6_half_nut", 6, 11.5, 3, 8, M6_washer, 3]; +M8_nut = ["M8_nut", 8, 15, 6.5, 8, M8_washer, M8_nut_depth]; +toggle_nut = ["toggle_nut", 6.1, 9.2, 1.5, 1.5, M6_washer, 1.5]; + +M4_wingnut = ["M4_wingnut", 4, 10, 3.75,8, M4_washer, 0, 22, 10, 6, 3]; + +nuts = [M2_nut, M2p5_nut, M3_nut, M4_nut, M5_nut, M6_nut, M8_nut]; + +use diff --git a/vitamins/o_ring.scad b/vitamins/o_ring.scad new file mode 100644 index 0000000..2f6c777 --- /dev/null +++ b/vitamins/o_ring.scad @@ -0,0 +1,40 @@ +// +// 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 . +// + +// +//! Nitrile rubber O-rings. +//! +//! Just a black torus specified by internal diameter, ```id``` and ```minor_d``` plus a BOM entry. +//! Can be shown stretched by specifying the ```actual_id```. +// +include <../core.scad> + +module O_ring(id, minor_d, actual_id = 0) { //! Draw O-ring with specified internal diameter and minor diameter. ```actual_id``` can be used to stretch it around something. + vitamin(str("O_ring(", id, ", ", minor_d, "): O-ring nitrile ", id, "mm x ", minor_d, "mm")); + + D = actual_id > id ? actual_id : id; // allow it to be stretched + // + // assume volume conserved when stretched. It is proportional to major diameter and square of minor diameter + // + r = (minor_d / 2) * sqrt(id / D); + R = D / 2 + r / 2; + color([0.2, 0.2, 0.2]) rotate_extrude() + translate([R, 0]) + circle(r = r); +} diff --git a/vitamins/opengrab.scad b/vitamins/opengrab.scad new file mode 100644 index 0000000..54957ef --- /dev/null +++ b/vitamins/opengrab.scad @@ -0,0 +1,93 @@ +// +// 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 . +// + +// +//! Nicodrone OpenGrab V3 electro-permananet magnet, see . +//! +//! A permanent magnet that can be magnatized and de-magnatized electronically. +// +include <../core.scad> + +pitch = 33.8; +width = 40; +depth = 18; +magnet = 4.3; +pcb = 0.8; +pillar = 6; +target = 1; +pole_w = 2; +pole_l = 36; +poles = 15; + +module opengrab_hole_positions() //! Position children at the screw positions + for(x = [-1, 1], y = [-1, 1]) + translate([x * pitch / 2, y * pitch / 2, 0]) + children(); + + +function opengrab_width() = width; //! Module width +function opengrab_depth() = depth; //! Module height +function opengrab_target_thickness() = target; //! Target sheet thickness + +module opengrab() { //! Draw OpenGrab module + vitamin("opengrab(): OpenGrab V3 electro permanent magnet"); + + color("grey") + translate_z(magnet / 2 + eps) + cube([width, width, magnet - eps], center = true); + + color(grey80) { + gap = (width - poles * pole_w + 3 * eps) / (poles - 1); + pitch = pole_w + gap; + for(i = [0 : poles - 1]) + translate([(i - floor(poles / 2)) * pitch - eps, 0, 0.5]) + cube([pole_w, pole_l, 1], center = true); + } + + color("darkgreen") + translate_z(depth - pillar - pcb / 2) + cube([width, width, pcb], center = true); + + color(brass) + translate_z(1) + opengrab_hole_positions() + linear_extrude(height = depth - 1) + difference() { + circle(d = 4.7 / cos(30), $fn = 6); + + circle(r = 3/2); + } +} + +module opengrab_target() { //! Draw OpenGrab target + vitamin("opengrab_target(): OpenGrab silicon steel target plate"); + + color(grey80) + linear_extrude(height = target) + difference() { + square([width, width], center = true); + + opengrab_hole_positions() + circle(d = 3.2); + + for(side = [-1, 1]) + translate([side * (width / 2 - 3.5), 0]) + circle(d = 4); + } +} diff --git a/vitamins/pcb.scad b/vitamins/pcb.scad new file mode 100644 index 0000000..5ab39e6 --- /dev/null +++ b/vitamins/pcb.scad @@ -0,0 +1,996 @@ +// +// 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 . +// + +// +//! PCBs and perfboard with optional components. The shape can be a rectangle with optionally rounded corners or a polygon for odd shapes like Arduino. +// +panel_clearance = 0.2; + +include <../core.scad> +include +include +use <../utils/rounded_cylinder.scad> +use <../utils/dogbones.scad> +use <../utils/tube.scad> +use + +function pcb_name(type) = type[1]; //! Description +function pcb_length(type) = type[2]; //! Length +function pcb_width(type) = type[3]; //! Width +function pcb_thickness(type) = type[4]; //! Thickness +function pcb_radius(type) = type[5]; //! Corner radius +function pcb_hole_d(type) = type[6]; //! Mounting hole diameter +function pcb_land_d(type) = type[7]; //! Pad around mounting hole +function pcb_colour(type) = type[8]; //! Colour of the subtrate +function pcb_parts_on_bom(type) = type[9]; //! True if the parts should be separate BOM items +function pcb_holes(type) = type[10]; //! List of hole positions +function pcb_components(type) = type[11]; //! List of components +function pcb_accessories(type) = type[12]; //! List of accessories to go on the BOM, SD cards, USB cables, etc. +function pcb_grid(type) = type[13]; //! Grid if a perfboard +function pcb_polygon(type) = type[14]; //! Optional outline polygon for odd shaped boards +function pcb_screw(type, cap = hs_cap) = Len(type[15]) ? type[15] : find_screw(cap, screw_smaller_than(pcb_hole_d(type))); //! Mounting screw type + +module pcb_grid(type, x, y, z = 0) //! Positions children at specified grid positions + translate([-pcb_length(type) / 2 + pcb_grid(type).x + 2.54 * x, + -pcb_width(type) / 2 + pcb_grid(type).y + 2.54 * y, pcb_thickness(type) + z]) + children(); + +// allows negative ordinates to represent offsets from the far edge +function pcb_coord(type, p) = let(l = pcb_length(type), w = pcb_width(type)) //! Convert offsets from the edge to coordinates relative to the centre + [(p.x > 0 ? p.x : l + p.x) - l / 2, + (p.y > 0 ? p.y : w + p.y) - w / 2]; + +module pcb_screw_positions(type) { //! Positions children at the mounting hole positions + holes = pcb_holes(type); + + if(len(holes)) + for($i = [0 : len(holes) - 1]) { + p = pcb_coord(type, holes[$i]); + translate([p.x, p.y, 0]) + children(); + } +} +// p p b p p b +// i i e i i a +// t n l n n s +// c o e +// h l w w c +// c +// +2p54header = ["2p54header", 2.54, 12, 3.2, 0.66, "gold", grey20, 8.5]; + +function hdr_pitch(type) = type[1]; //! Header pitch +function hdr_pin_length(type) = type[2]; //! Header pin length +function hdr_pin_below(type) = type[3]; //! Header pin length underneath +function hdr_pin_width(type) = type[4]; //! Header pin size +function hdr_pin_colour(type) = type[5]; //! Header pin colour +function hdr_base_colour(type) = type[6]; //! Header insulator colour +function hdr_socket_depth(type) = type[7]; //! Socket depth for female housing + +module pin(type = 2p54header, length = undef) { //! Draw a header pin + w = hdr_pin_width(type); + l = length == undef ? hdr_pin_length(type) : length; + chamfer = w / 2; + color(hdr_pin_colour(type)) + translate_z(l / 2 -hdr_pin_below(type)) + hull() { + cube([w, w, l - 2 * chamfer], center = true); + + cube([w - chamfer, w - chamfer, l], center = true); + } + } + +module pin_header(type = 2p54header, cols = 1, rows = 1, smt = false, cutout = false) { //! Draw pin header + pitch = hdr_pitch(type); + h = pitch; + + if(cutout) + dogbone_rectangle([cols * pitch + 2 * panel_clearance, rows * pitch + 2 * panel_clearance, 100], center = false); + else + vitamin(str("pin_header(", type[0], cols, rows, arg(smt, false, "smt"), "): Pin header ", cols, " x ", rows)); + + translate_z(smt ? 3.5 - h : 0) { + for(x = [0 : cols - 1], y = [0 : rows - 1]) + translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2), 0]) + pin(type); + + color(hdr_base_colour(type)) + linear_extrude(height = h) + for(x = [0 : cols - 1], y = [0 : rows - 1]) + translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2), pitch / 2]) + hull() { + chamfer = pitch / 4; + square([pitch + eps, pitch - chamfer], center = true); + + square([pitch - chamfer, pitch + eps], center = true); + } + } +} + +module idc_transition(type, cols = 5, skip = [], cutout = false) { //! Draw IDC transition header + rows = 2; + pitch = hdr_pitch(type); + height = 7.4; + width = 6; + length = cols * pitch + 5.08; + if(cutout) + ; + else { + vitamin(str("idc_transition(", type[0], ", ", cols, "): IDC transition header ", cols, " x ", rows)); + + color(hdr_base_colour(type)) + rotate([90, 0, 0]) + linear_extrude(height = width, center = true, convexity = cols * rows) + difference() { + translate([0, height / 2]) + square([length, height], center = true); + + for(i = [0 : cols * rows - 1]) + translate([pitch / 2 * (i - (cols * rows - 1) / 2), height / 2]) + circle(d = pitch / 2 + eps); + + slot = pitch / 3; + translate([0, height / 2 - pitch / 4 + slot / 2]) + square([cols * pitch, slot], center = true); + } + + for(x = [0 : cols - 1], y = [0 : rows -1]) + if(!in(skip, x)) + translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2), 0]) + pin(type, 2); + } +} + +module pin_socket(type = 2p54header, cols = 1, rows = 1, right_angle = false, height = 0, cutout = false) { //! Draw pin socket + pitch = hdr_pitch(type); + length = pitch * cols + 0.5; + width = pitch * rows - 0.08; + depth = max(hdr_socket_depth(type), height); + ra_offset = 1.5; + if(cutout) + ; + else { + vitamin(str("pin_socket(", type[0], ", ", cols, ", ", rows, arg(right_angle, false, "right_angle"), arg(height, 0, "height"), + "): Pin socket ", cols, " x ", rows, right_angle ? " right_angle" : "")); + color(hdr_base_colour(type)) + translate([0, right_angle ? -ra_offset - pitch / 2 : 0, right_angle ? width / 2 : 0]) + rotate([right_angle ? 90 : 0, 0, 0]) + translate_z(depth / 2) + linear_extrude(height = depth, center = true) + difference() { + square([length, width], center = true); + + for(x = [0 : cols - 1], y = [0 : rows -1]) + translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2)]) + square(hdr_pin_width(type), center = true); + } + + color(hdr_pin_colour(type)) + for(x = [0 : cols - 1], y = [0 : rows -1]) { + translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2), 0]) + pin(type, hdr_pin_below(type) + width / 2 + (y - 0.5) * pitch); + + if(right_angle) { + rotate([-90, 0, 0]) + translate([pitch * (x - (cols - 1) / 2), -pitch * (y - (rows - 1) / 2) -width / 2, 0]) + pin(type, hdr_pin_below(type) + (y - 0.5) * pitch); + + w = hdr_pin_width(type); + translate([pitch * (x - (cols - 1) / 2), pitch * (y - (rows - 1) / 2) - w / 2, pitch * (y - (rows - 1) / 2) + width / 2 - w / 2]) + rotate([0, -90, 0]) + rotate_extrude(angle = 90, $fn = 32) + translate([0, -w / 2]) + square(w); + } + } + } +} + +module chip(length, width, thickness, cutout = false) //! Draw a black cube to represent a chip + if(!cutout) + color(grey20) + translate_z(thickness / 2) cube([length, width, thickness], center = true); + +module usb_Ax2(cutout = false) { //! Draw USB type A dual socket + l = 17; + w = 13.25; + h = 15.6; + flange_t = 0.4; + h_flange_h = 0.8; + h_flange_l = 11; + v_flange_h = 1; + v_flange_l = 12.15; + bar = 3.4; + socket_h = (h - 2 * flange_t - bar) / 2; + + translate_z(h / 2) + if(cutout) + rotate([90, 0, 90]) + rounded_rectangle([w + 2 * v_flange_h + 2 * panel_clearance, + h + 2 * h_flange_h + 2 * panel_clearance, 100], r = cnc_bit_r, center = false); + else + color("silver") rotate([0, 90, 0]) { + linear_extrude(height = l, center = true) + difference() { + square([h, w], center = true); + + for(s = [-1, 1]) + translate([s * (bar / 2 + socket_h / 2), 0]) + square([socket_h, w - 2 * flange_t], center = true); + } + + translate_z(-l / 2 + 0.5) + cube([h, w, 1], center = true); + + translate_z(l / 2 - flange_t) + linear_extrude(height = flange_t) difference() { + union() { + square([h + 2 * h_flange_h, h_flange_l], center = true); + + square([v_flange_l, w + 2 * v_flange_h], center = true); + } + square([h - eps, w - eps], center = true); + } + } +} + +module rj45(cutout = false) { //! Draw RJ45 Ethernet connector + l = 21; + w = 16; + h = 13.5; + + plug_h = 6.8; + plug_w = 12; + plug_z = 4; + + tab_z = 0.8; + tab_w = 4; + + translate_z(h / 2) + if(cutout) + rotate([90, 0, 90]) + dogbone_rectangle([w + 2 * panel_clearance, h + 2 * panel_clearance, 100], center = false); + else { + rotate([0, 90, 0]) { + mouth = plug_z + plug_h - tab_z; + color("silver") { + linear_extrude(height = l, center = true) + difference() { + square([h, w], center = true); + + translate([h / 2 - tab_z - mouth / 2, 0]) + square([mouth + 0.1, plug_w + 0.1], center = true); + } + + translate_z(-l / 2) + cube([h, w, eps], center = true); + } + + color(grey30) { + linear_extrude(height = l - 0.2, center = true) + difference() { + square([h - 0.1, w - 0.1], center = true); + + translate([h / 2 - plug_z - plug_h / 2, 0]) + square([plug_h, plug_w - 0.1], center = true); + + translate([h / 2 - tab_z - plug_h / 2, 0]) + square([plug_h, tab_w], center = true); + } + + translate_z(-l / 2 + 1) + cube([h - 0.1, w - 0.1, 0.1], center = true); + } + } + } +} + +module jack(cutout = false) { //! Draw 3.5mm jack + l = 12; + w = 7; + h = 6; + d = 6; + ch = 2.5; + + translate_z(h / 2) + if(cutout) + rotate([0, 90, 0]) + cylinder(d = d + 2 * panel_clearance, h = 100); + else + color(grey20) + rotate([0, 90, 0]) { + linear_extrude(height = l / 2) + difference() { + square([h, w], center = true); + + circle(d = 3.5); + } + + tube(or = d / 2, ir = 3.5 / 2, h = l / 2 + ch, center = false); + + translate_z(-l / 4) + cube([h, w, l / 2], center = true); + } +} + +module hdmi(cutout = false) { //! Draw HDMI socket + l = 12; + iw1 = 14; + iw2 = 10; + ih1 = 3; + ih2 = 4.5; + h = 6.5; + t = 0.5; + + module D() { + hull() { + translate([-iw1 / 2, h - t - ih1]) + square([iw1, ih1]); + + translate([-iw2 / 2, h - t - ih2]) + square([iw2, ih2]); + } + } + + if(cutout) + rotate([90, 0, 90]) + linear_extrude(height = 100) + offset(t + panel_clearance) + D(); + else + color("silver") + rotate([90, 0, 90]) { + linear_extrude(height = l, center = true) + difference() { + offset(t) + D(); + D(); + } + + translate_z(-l / 2) + linear_extrude(height = 1) + offset(t) + D(); + } +} + +module usb_uA(cutout = false) { //! Draw USB micro A connector + l = 6; + iw1 = 7; + iw2 = 5.7; + ih1 = 1; + ih2 = 1.85; + h = 2.65; + t = 0.4; + flange_h = 3; + flange_w = 8; + + module D() { + hull() { + translate([-iw1 / 2, h - t - ih1]) + square([iw1, ih1]); + + translate([-iw2 / 2, h - t - ih2]) + square([iw2, ih2]); + } + } + + if(cutout) + rotate([90, 0, 90]) + linear_extrude(height = 100) + offset((flange_h - ih2) / 2 + 2 * panel_clearance) + D(); + else + color("silver") rotate([90, 0, 90]) { + linear_extrude(height = l, center = true) + difference() { + offset(t) + D(); + + D(); + } + + translate_z(-l / 2) + linear_extrude(height = 1) + offset(t) + D(); + + translate_z(l / 2 - t) + linear_extrude(height = t) difference() { + union() { + translate([0, h - t - ih1 / 2]) + square([flange_w, ih1], center = true); + + translate([0, h / 2 + flange_h / 4]) + square([iw1, flange_h / 2], center = true); + + translate([0, h / 2 - flange_h / 4]) + square([iw2, flange_h / 2], center = true); + } + D(); + } + } +} + +module usb_B(cutout = false) { //! Draw USB B connector + l = 16.4; + w = 12.2; + h = 11; + tab_w = 5.6; + tab_h = 3.2; + d_h = 7.78; + d_w = 8.45; + d_w2 = 5; + d_h2 = d_h - (d_w - d_w2) / 2; + + module D() + hull() { + translate([-d_w / 2, 0]) + square([d_w, d_h2]); + translate([-d_w2 /2, 0]) + square([d_w2, d_h]); + } + + + if(cutout) + translate([50, 0, h / 2 - panel_clearance]) + cube([100, w + 2 * panel_clearance, h + 2 * panel_clearance], center = true); + else + translate_z(h / 2) rotate([90, 0, 90]) { + color("silver") { + linear_extrude(height = l, center = true) + difference() { + square([w, h], center = true); + + translate([0, -d_h / 2]) + offset(delta = 0.2) + D(); + } + translate_z(-l / 2 + 0.1) + cube([w, h, 0.2], center = true); + } + + color("white") { + linear_extrude(height = l - 0.4, center = true) + difference() { + square([w - 0.2, h - 0.2], center = true); + + translate([0, -d_h / 2]) + difference() { + D(); + + translate([0, d_h / 2]) + square([tab_w, tab_h], center = true); + } + } + translate_z( -(l - 0.4) / 2 + 1) + cube([w - 0.2, h - 0.2, 2], center = true); + } + } +} + +module barrel_jack(cutout = false) { //! Draw barrel power jack + l = 13.2; + w = 8.89; + h = 11; + bore_d = 6.3; + bore_h = 6.5; + bore_l = 11.8; + pin_d = 2; + front = 3.3; + r = 0.5; + contact_d = 2; + contact_w = 4; + inset = 1; + if(cutout) + ; + else { + color(grey20) rotate([0, 90, 0]) { + linear_extrude(height = l, center = true) { + difference() { + translate([-h / 2, 0]) + rounded_square([h, w], r); + + translate([-bore_h, 0]) + circle(d = bore_d); + + translate([-h / 2 - bore_h, 0]) + square([h, w], center = true); + + } + } + translate_z(l / 2 - front) + linear_extrude(height = front) { + difference() { + translate([-h / 2, 0]) + rounded_square([h, w], r); + + translate([-bore_h, 0]) + circle(d = bore_d); + } + } + + translate([-bore_h, 0]) + tube(or = w / 2 - 0.5, ir = bore_d / 2, h = l); + + translate([-bore_h, 0, -l / 2]) + cylinder(d = w -1, h = l - bore_l); + } + color("silver") { + translate([l / 2 - inset - pin_d / 2, 0, bore_h]) + hull() { + sphere(pin_d / 2); + + rotate([0, -90, 0]) + cylinder(d = pin_d, h = bore_l - inset); + } + hull() { + translate([l / 2 - inset - contact_d / 2, 0, bore_h - bore_d / 2]) + rotate([90, 0, 0]) + cylinder(d = contact_d, h = contact_w, center = true); + + translate([l / 2 - bore_l, 0, bore_h - bore_d / 2 + contact_d / 4]) + cube([eps, contact_w, eps], center = true); + } + } + } +} + +module flex(cutout = false) { //! Draw flexistrip connector + l = 20.6; + w = 3; + h = 5.6; + top_l = 22.4; + top_t = 1.1; + tab_l = 13; + tab_w = 1; + slot_l = 16.4; + slot_w = 0.7; + slot_offset = 0.6; + + if(cutout) + ; + else { + color(grey30) { + translate_z(0.5) + cube([l, w, 1], center = true); + + linear_extrude(height = h) + difference() { + square([l, w], center = true); + + translate([0, -w / 2 + slot_offset + slot_w / 2]) + square([slot_l, slot_w], center = true); + } + + translate_z(h - top_t) + linear_extrude(height = top_t) + difference() { + union() { + square([top_l, w], center = true); + + hull() { + translate([0, -w / 2 + (w + tab_w) / 2]) + square([tab_l - 1, w + tab_w], center = true); + + square([tab_l, w], center = true); + } + } + + translate([0, -w / 2 + slot_offset + slot_w / 2]) + square([slot_l, slot_w], center = true); + + } + } + } +} + +module terminal_35(ways) { //! Draw 3.5mm terminal block + vitamin(str("terminal_35(", ways, "): Terminal block ", ways, " way 3.5mm")); + pitch = 3.5; + width = ways * pitch; + depth = 7; + height = 8.3; + chamfer_h = 3; + chamfer_d = 1; + box_z = 0.5; + box_w = 2.88; + box_h = 4.1; + wire_z = 2; + wire_d = 2; + pin_l = 4.2; + pin_d = 0.9; + + module single() { + screw_r = 1; + color("blue") { + rotate([90, 0, 0]) + linear_extrude(height = pitch, center = true) + polygon(points = [ + [ depth / 2, 0], + [ depth / 2, box_z], + [-depth / 2 + 1, box_z], + [-depth / 2 + 1, box_z + box_h], + [ depth / 2, box_z + box_h], + [ depth / 2, height - chamfer_h], + [ depth / 2 - chamfer_d, height], + [ -screw_r - eps, height], + [ -screw_r - eps, box_z + box_h], + [ screw_r + eps, box_z + box_h], + [ screw_r + eps, height], + [-depth / 2, height], + [-depth / 2, 0], + ]); + + linear_extrude(height = box_z + box_h) + difference() { + square([depth, pitch], center = true); + + translate([1, 0]) + square([depth, box_w], center = true); + + + } + + translate_z(box_z + box_h) + linear_extrude(height = height - box_z - box_h) + difference() { + square([2 * screw_r + 0.1, pitch], center = true); + + circle(screw_r); + } + } + color("silver") { + screw_z = box_z + box_h; + translate_z(screw_z) { + cylinder(r = screw_r, h = height - screw_z - 1); // screw + + linear_extrude(height = height - screw_z - 0.5) + difference() { + circle(1); + + square([4, 0.5], center = true); // screw slot + + square([0.5, 1.7], center = true); // second screw slot + } + + } + translate_z(box_z - pin_l) + cylinder(d = pin_d, h = pin_l + box_z, $fn = 16); // pin + + translate_z(box_z + box_h / 2) // terminal + rotate([0, -90, 0]) { + linear_extrude(height = depth - 2, center = true) + difference() { + square([box_h, box_w], center = true); + + translate([wire_z - box_z - box_h / 2, 0]) + circle(d = wire_d); + } + translate_z(depth / 2 - 1.5) + cube([box_h, box_w, 1], center = true); + } + } + } + for(i = [0: ways -1]) + translate([0, i * pitch - width / 2 + pitch / 2]) + single(); +} + +module terminal_254(ways, skip = []) { //! Draw 0.1" terminal block + vitamin(str("terminal_254(", ways, "): Terminal block ", ways, " way 0.1\"")); + pitch = 2.54; + width = ways * pitch; + depth = 6.2; + height = 8.5; + ledge_height = 5; + ledge_depth = 0.7; + top = 3; + back = 3; + module single(skip = false) { + screw_r = 1; + box_w1 = pitch - 0.4; + box_h1 = ledge_height - 0.4; + box_w2 = 2; + box_h2 = 2; + color("lime") { + rotate([90, 0, 0]) + linear_extrude(height = pitch, center = true, convexity = 5) + polygon(points = [ + [ depth / 2, 0], + [ depth / 2, ledge_height / 2 - box_h1 / 2], + [ depth / 2 - 0.5, ledge_height / 2 - box_h1 / 2], + [ depth / 2 - 2, ledge_height / 2 - box_h2 / 2], + [-depth / 2 + 1, ledge_height / 2 - box_h2 / 2], + [-depth / 2 + 1, ledge_height / 2 + box_h2 / 2], + [ depth / 2 - 2, ledge_height / 2 + box_h2 / 2], + [ depth / 2 - 0.5, ledge_height / 2 + box_h1 / 2], + [ depth / 2, ledge_height / 2 + box_h1 / 2], + [ depth / 2, ledge_height], + [ depth / 2 - ledge_depth, ledge_height], + [ top / 2, height], + [ screw_r + eps, height], + [ screw_r + eps, ledge_height / 2 + box_h2 / 2], + [-screw_r - eps, ledge_height / 2 + box_h2 / 2], + [-screw_r - eps, height], + [ -top / 2, height], + [-depth / 2, back], + [-depth / 2, 0], + ]); + + translate_z(ledge_height / 2 + box_h2 / 2) + linear_extrude(height = height - ledge_height / 2 - box_h2 / 2) + difference() { + square([screw_r * 2 + 0.1, pitch], center = true); + + circle(screw_r); + } + + linear_extrude(height = ledge_height) + difference() { + translate([0.5, 0]) + square([depth - 1, pitch], center = true); + + + translate([depth / 2, 0]) { + square([9, box_w2], center = true); + + hull() { + square([1, box_w1], center = true); + square([4, box_w2], center = true); + } + } + } + } + if(!skip) + color("silver") + translate_z(1) { + slot_depth = 1; + screw_top = height - 1.5; + pin_l = 3.3 + ledge_height / 2 - 2; + translate_z(ledge_height / 2) // screw + cylinder(r = 1, h = screw_top - slot_depth - ledge_height / 2); + + translate_z(screw_top - slot_depth) // screw head + linear_extrude(height = slot_depth) + difference() { + circle(1); + square([4, 0.5], center = true); + } + + translate_z(ledge_height / 2 - 1) + rotate([0, 90, 0]) + linear_extrude(height = 2, center = true) + difference() { + square([2, 2], center = true); + + square([1.5, 1.9], center = true); + + } + + translate([-1.5, 0, ledge_height / 2 - 1]) // terminal back + cube([1, 2, 2], center = true); + + translate_z(ledge_height / 2 - 2 - pin_l / 2) + cube([0.44, 0.75, pin_l], center = true); // pin + } + } + for(i = [0: ways -1]) + translate([0, i * pitch - width / 2 + pitch / 2]) + single(in(skip, i)); +} + +module molex_254(ways) { //! Draw molex header + vitamin(str("molex_254(", ways, "): Molex KK header ", ways, " way")); + pitch = 2.54; + width = ways * pitch - 0.1; + depth = 6.35; + height = 8.15; + base = 3.18; + back = 1; + below = 2.3; + above = 9; + color("white") + union() { + translate([ -depth / 2, -width / 2,]) + cube([depth, width, base]); + + w = width - pitch; + translate([- depth / 2, -w / 2]) + cube([back, w, height]); + } + + color("silver") + for(i = [0: ways -1]) + translate([0, i * pitch - width / 2 + pitch / 2, (above + below) / 2 - below]) + cube([0.44, 0.75, above + below], center = true); +} + +module pcb_component(comp, cutouts = false, angle = undef) { //! Draw pcb component from description + function show(comp, part) = (comp[3] == part || comp[3] == str("-",part)) && (!cutouts || angle == undef || angle == comp.z); + rotate(comp.z) { + if(show(comp, "2p54header")) pin_header(2p54header, comp[4], comp[5], len(comp) > 5 ? comp[6] : false, cutouts); + if(show(comp, "2p54socket")) pin_socket(2p54header, comp[4], comp[5], comp[6], len(comp) > 7 ? comp[7] : 0, cutouts); + if(show(comp, "chip")) chip(comp[4], comp[5], comp[6], cutouts); + if(show(comp, "rj45")) rj45(cutouts); + if(show(comp, "usb_Ax2")) usb_Ax2(cutouts); + if(show(comp, "usb_uA")) usb_uA(cutouts); + if(show(comp, "usb_B")) usb_B(cutouts); + if(show(comp, "jack")) jack(cutouts); + if(show(comp, "barrel_jack")) barrel_jack(cutouts); + if(show(comp, "hdmi")) hdmi(cutouts); + if(show(comp, "flex")) flex(cutouts); + if(show(comp, "D_plug")) if(!cutouts) translate_z(d_pcb_offset(comp[4])) d_plug(comp[4], pcb = true); + if(show(comp, "molex_hdr")) if(!cutouts) molex_254(comp[4]); + if(show(comp, "term254")) if(!cutouts) terminal_254(comp[4], comp[5]); + if(show(comp, "term35")) if(!cutouts) terminal_35(comp[4]); + if(show(comp, "transition")) if(!cutouts) idc_transition(2p54header, comp[4], comp[5]); + if(show(comp, "block")) + color(comp[7]) if(!cutouts) translate_z(comp[6] / 2) cube([comp[4], comp[5], comp[6]], center = true); + else if(comp[8]) translate([-50, 0, comp[6] / 2 - panel_clearance]) cube([100, comp[5] + 2 * panel_clearance, comp[6] + 2 * panel_clearance], center = true); + if(show(comp, "button_6mm")) square_button(button_6mm); + } +} + +module pcb_components(type, cutouts = false, angle = undef) { //! Draw list of PCB components on the PCB + not_on_bom(pcb_parts_on_bom(type)) + for(comp = pcb_components(type)) { + p = pcb_coord(type, [comp.x, comp.y]); + if(comp[3][0] == "-") + translate([p.x, p.y]) + vflip() + pcb_component(comp, cutouts, angle); + else + translate([p.x, p.y, pcb_thickness(type)]) + pcb_component(comp, cutouts, angle); + } +} + +module pcb_cutouts(type, angle = undef) pcb_components(type, true, angle); //! Make cut outs to clear components on a PCB + +module pcb_grid_positions(type) { + x0 = pcb_grid(type).x; + y0 = pcb_grid(type).y; + + cols = round((pcb_length(type) - 2 * x0) / inch(0.1)); + rows = round((pcb_width(type) - 2 * y0) / inch(0.1)); + for(x = [0 : cols], y = [0 : rows]) + pcb_grid(type, x, y) + children(); +} + +module pcb(type) { //! Draw specified PCB + grid = pcb_grid(type); + t = pcb_thickness(type); + if(pcb_name(type)) + vitamin(str("pcb(", type[0], "): ", pcb_name(type))); + + for(part = pcb_accessories(type)) + vitamin(part); + + pcb_components(type); + + color(pcb_colour(type)) linear_extrude(height = t) difference() { + if(Len(pcb_polygon(type))) + polygon(pcb_polygon(type)); + else + rounded_square([pcb_length(type), pcb_width(type)], r = pcb_radius(type)); + + pcb_screw_positions(type) + circle(d = pcb_hole_d(type) + eps); + + if(Len(grid)) + pcb_grid_positions(type) + circle(d = 1 + eps); + } + + color("silver") + translate_z(t / 2) + pcb_screw_positions(type) + tube(or = max(pcb_land_d(type), 1) / 2, ir = pcb_hole_d(type) / 2, h = t + 2 * eps); + + fr4 = pcb_colour(type) == "green"; + plating = 0.15; + color(fr4 ? "silver" : "gold") + translate_z(-plating) + linear_extrude(height = fr4 ? t + 2 * plating : plating) + if(Len(grid)) { + pcb_grid_positions(type) + difference() { + circle(d = 2); + + circle(d = 1); + } + if(fr4) { // oval lands at the ends + screw_x = pcb_coord(type, pcb_holes(type)[0]).x; + y0 = pcb_grid(type).y; + rows = round((pcb_width(type) - 2 * y0) / inch(0.1)); + for(end = [-1, 1], y = [1 : rows - 1]) + translate([end * screw_x, y0 + y * inch(0.1) - pcb_width(type) / 2]) + hull() + for(x = [-1, 1]) + translate([x * 1.6 / 2, 0]) + circle(d = 2); + } + } +} + +module pcb_spacer(screw, height, wall = 1.8) { //! Generate STL for PCB spacer + stl(str("pcb_spacer", round(screw_radius(screw) * 20), round(height * 10))); + + ir = screw_clearance_radius(screw); + or = corrected_radius(ir) + wall; + + linear_extrude(height = height) + poly_ring(or, ir); +} + +module pcb_base(type, height, thickness, wall = 2) { //! Generate STL for a base with PCB spacers + screw = pcb_screw(type); + ir = screw_clearance_radius(screw); + or = corrected_radius(ir) + wall; + + union() { + linear_extrude(height = thickness) + difference() { + hull() + pcb_screw_positions(type) + poly_ring(or, ir); + + pcb_screw_positions(type) + poly_circle(ir); + } + + linear_extrude(height = height) + pcb_screw_positions(type) + poly_ring(or, ir); + } +} + +module pcb_assembly(type, height, thickness) { //! Draw PCB assembly with spaces and fasteners in place + translate_z(height) + pcb(type); + + screw = pcb_screw(type); + if(!is_undef(screw)) { + washer = screw_washer(screw); + nut = screw_nut(screw); + screw_length = screw_longer_than(height + thickness + pcb_thickness(type) + washer_thickness(washer) + nut_thickness(nut, true)); + + taper = screw_smaller_than(pcb_hole_d(type)) > 2 * screw_radius(screw); // Arduino? + pcb_screw_positions(type) { + translate_z(height + pcb_thickness(type)) + screw(screw, screw_length); + + color(pp1_colour) + if(taper) { + h2 = max(0, height - 2); + if(h2) + pcb_spacer(screw, h2); + pcb_spacer(screw, height, 2 * extrusion_width); // Thin as can be at the top because there is no clearance around the holes. + } + else + pcb_spacer(screw, height); + + translate_z(-thickness) + vflip() + nut_and_washer(nut, true); + } + } +} diff --git a/vitamins/pcbs.scad b/vitamins/pcbs.scad new file mode 100644 index 0000000..e0f9942 --- /dev/null +++ b/vitamins/pcbs.scad @@ -0,0 +1,133 @@ +// +// 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 . +// +include +// +// l w t r h l c b h +// e i h a o a o o o +// n d i d l n l m l +// g t c i e d o e +// t h k u u s +// h n s d d r +// e +// s +// s +// +DuetW = ["DuetW", "Duet WiFi electronics", + 123, 100, 1.6, 0, 4.2, 0, "mediumblue", false, [[119, 4], [119, 96], [4, 96],[4, 4]], + [], + []]; + +Melzi = ["Melzi", "Melzi electronics", 203.2, 49.53, 1.6, 3.81, 3.1, 6, "green", false, [[3.81, 3.81], [-3.81, 3.81], [-3.81, -3.81], [3.81, -3.81]], + [], + [": USB A to Mini B lead", ": Micro SD card"]]; + +RPI3 = ["RPI3", "Raspberry Pi 3", 85, 56, 1.4, 3, 2.75, 6, "green", false, [[3.5, 3.5], [61.5, 3.5], [61.5, -3.5], [3.5, -3.5]], + [[32.5, -3.5, 0, "2p54header", 20, 2], + [27, -24.6, 0, "chip", 14, 14, 1], + [60, -22.3, 0, "chip", 9, 9, 0.6], + [-8.5, 10.25, 0, "rj45"], + [-6.5, 29, 0, "usb_Ax2"], + [-6.5, 47, 0, "usb_Ax2"], + [53.5, 6, -90, "jack"], + [32, 4.4, -90, "hdmi"], + [10.6, 2, -90, "usb_uA"], + [3.6, 28, 90, "flex"], + [45, 11.5,-90, "flex"], + ], + [": Micro SD card"]]; + +ArduinoUno3 = ["ArduinoUno3", "Arduino Uno R3", 68.58, 53.34, 1.6, 0, 3.3, 0, "mediumblue", false, [[15.24, 50.8],[66.04, 35.56],[66.04, 7.62],[13.97, 2.54]], + [[30.226, -2.54, 0, "2p54socket", 10, 1], + [54.61, -2.54, 0, "2p54socket", 8, 1], + [36.83, 2.54, 0, "2p54socket", 8, 1], + [57.15, 2.54, 0, "2p54socket", 6, 1], + [64.91, 27.89, 0, "2p54header", 2, 3], + [18.796, -7.00, 0, "2p54header", 3, 2], + [ 6.5, -3.5, 0, "button_6mm"], + [4.7625, 7.62, 180, "barrel_jack"], + [1.5875, 37.7825,180,"usb_B"], + ], + [],[], + inch([ + [-1.35, -1.05], + [-1.35, 1.05], + [ 1.19, 1.05], + [ 1.25, 0.99], + [ 1.25, 0.54], + [ 1.35, 0.44], + [ 1.35, -0.85], + [ 1.25, -0.95], + [ 1.25, -1.05], + ]), + M2p5_pan_screw + ]; + +Keyes5p1 = ["Keyes5p1", "Keyes5.1 Arduino Uno expansion board", 68.58, 53.34, 1.6, 0, 3.3, 0, "mediumblue", false, [[15.24, 50.8],[66.04, 35.56],[66.04, 7.62],[13.97, 2.54]], + [[30.226, -2.54, 0, "-2p54header", 10, 1], + [54.61, -2.54, 0, "-2p54header", 8, 1], + [36.83, 2.54, 0, "-2p54header", 8, 1], + [57.15, 2.54, 0, "-2p54header", 6, 1], + ], + [],[], + inch([ + [-1.35, -1.05], + [-1.35, 1.05], + [ 1.19, 1.05], + [ 1.25, 0.99], + [ 1.25, 0.54], + [ 1.35, 0.44], + [ 1.35, -0.85], + [ 1.25, -0.95], + [ 1.25, -1.05], + ]), + M2p5_pan_screw + ]; + + +ExtruderPCB = ["ExtruderPCB", "Extruder connection PCB", + 33.02, 24.13, 1.6, 0, 0, 0, "green", true, [], + [[3 * 1.27, 24.13 / 2, 90, "D_plug", DCONN15], + [-(8.89 + 2.75 * 2.54), 2.5 * 1.27 + 24.13 / 2, 90, "molex_hdr", 3], + [-(8.89 - 1.5 * 2.54), -3.5 * 1.27 + 24.13 / 2, -90, "molex_hdr", 2], + [-(8.89 - 2.54), 2.5 * 1.27 + 24.13 / 2, 90, "term254", 4], + [-(8.89 + 2 * 2.54), -3.5 * 1.27 + 24.13 / 2, -90, "term254", 4], + ], []]; + +PI_IO = ["PI_IO", "PI_IO V2", 35.56, 25.4, 1.6, 0, 0, 0, "green", true, [], + [[(3.015 - 2.7) * 25.4 - 3.5 /2, (4.5 - 3.685) * 25.4, 90, "term35", 2], + [(3.46 - 2.7) * 25.4 - 3.5 /2, (4.5 - 3.69) * 25.4, 90, "term35", 2], + [(3.91 - 2.7) * 25.4 - 3.5 /2, (4.5 - 3.69) * 25.4, 90, "term35", 2], + [(3.4 - 2.7) * 25.4, (4.5 - 4.15) * 25.4, 0, "2p54socket", 13, 2, true], + ], []]; + +PERF80x20 = ["PERF80x20", "Perfboard 80 x 20mm", 80, 20, 1.6, 0, 2.3, 0, "green", true, [[2,2],[-2,2],[2,-2],[-2,-2]], [], [], [5.87, 3.49]]; + +PERF70x50 = ["PERF70x50", "Perfboard 70 x 50mm", 70, 50, 1.6, 0, 2.3, 0, "green", true, [[2,2],[-2,2],[2,-2],[-2,-2]], [], [], [5.87, 3.49]]; + +PERF70x30 = ["PERF70x30", "Perfboard 70 x 30mm", 70, 30, 1.6, 0, 2.3, 0, "green", true, [[2,2],[-2,2],[2,-2],[-2,-2]], [], [], [5.87, 3.49]]; + +PERF60x40 = ["PERF60x40", "Perfboard 60 x 40mm", 60, 40, 1.6, 0, 2.3, 0, "green", true, [[2,2],[-2,2],[2,-2],[-2,-2]], [], [], [5.87, 3.49]]; + +PERF74x51 = ["PERF74x51", "Perfboard 74 x 51mm", 74, 51, 1.0, 0, 3.0, 0, "sienna", true, [[3.0, 3.5], [-3.0, 3.5], [3.0, -3.5], [-3.0, -3.5]], [], [], [9.5, 4.5]]; + +PSU12V1A = ["PSU12V1A", "PSU 12V 1A", 67, 31, 1.7, 0, 3.9, 0, "green", true, [[3.5, 3.5], [-3.5, 3.5], [-3.5, -3.5], [3.5, -3.5]], [], []]; + +pcbs = [ExtruderPCB, PI_IO, RPI3, ArduinoUno3, Keyes5p1, PERF80x20, PERF70x50, PERF70x30, PERF60x40, PERF74x51, PSU12V1A, DuetW, Melzi]; + +use diff --git a/vitamins/pillar.scad b/vitamins/pillar.scad new file mode 100644 index 0000000..3eb72b5 --- /dev/null +++ b/vitamins/pillar.scad @@ -0,0 +1,76 @@ +// +// 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 . +// + +// +//! Threaded pillars. Each end can be male or female. +// +include <../core.scad> + +function pillar_name(type) = type[1]; //! Name of part +function pillar_thread(type) = type[2]; //! Thread diameter +function pillar_height(type) = type[3]; //! Body height +function pillar_od(type) = type[4]; //! Outer diameter of body +function pillar_id(type) = type[5]; //! Inner diameter of metal part +function pillar_ofn(type) = type[6]; //! Outer number of sides, 6 for hex, 0 for smooth cylinder +function pillar_ifn(type) = type[7]; //! Inner number of sides, 6 for hex, 0 for smooth cylinder +function pillar_o_colour(type) = type[8]; //! Colour of the outer part +function pillar_i_colour(type) = type[9]; //! Colour of the inner part +function pillar_top_thread(type) = type[10]; //! Top thread length, + for male, - for female +function pillar_bot_thread(type) = type[11]; //! Bottom thread length, + for male, - for female + +module pillar(type) { //! Draw specified pillar + function sex(thread) = thread > 0 ? "M" : "F"; + function fn(n) = n ? n : $fn; + + sex = str(sex(pillar_bot_thread(type)),"/", sex(pillar_top_thread(type))); + height = pillar_height(type); + thread_d = pillar_thread(type); + + vitamin(str("pillar(", type[0], "): Pillar ", pillar_name(type), " ", sex, " M", thread_d, "x", height)); + + color(pillar_i_colour(type)) { + if(pillar_bot_thread(type) > 0) + translate_z(-pillar_bot_thread(type)) + cylinder(h = pillar_bot_thread(type) + eps, d = pillar_thread(type)); + + if(pillar_top_thread(type) > 0) + translate_z(height - eps) + cylinder(h = pillar_top_thread(type) + eps, d = pillar_thread(type)); + + linear_extrude(height = height) + difference() { + circle(d = pillar_id(type), $fn = fn(pillar_ifn(type))); + circle(d = pillar_thread(type)); + } + + top = height + min(pillar_top_thread(type), 0); + bot = -min(pillar_bot_thread(type), 0); + + translate_z(bot) + cylinder(h = top - bot, d = pillar_thread(type) + eps); + } + if(pillar_od(type) > pillar_id(type)) + color(pillar_o_colour(type)) linear_extrude(height = height) + difference() { + circle(d = pillar_od(type), $fn = fn(pillar_ofn(type))); + + circle(d = pillar_id(type), $fn = fn(pillar_ifn(type))); + } + +} diff --git a/vitamins/pillars.scad b/vitamins/pillars.scad new file mode 100644 index 0000000..540ad2d --- /dev/null +++ b/vitamins/pillars.scad @@ -0,0 +1,43 @@ +// +// 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 . +// + +// +// Nylon pillars +// +// n t h o i o i o i b t +// a h e d d f f +// m r i n n c c t t +// e e g o o h h +// a h l l r r +// d t o o e e +// u u a a +// d r r d d +// +M2x16_brass_pillar = ["M2x16_brass_pillar", "nurled", 2, 16, 3.17, 3.17, 0, 0, "gold", "gold", 3,-3]; +M3x13_hex_pillar = ["M3x13_hex_pillar", "hex", 3, 13, 5/cos(30), 5/cos(30), 6, 6, "silver", "silver", -6, 6]; +M3x20_hex_pillar = ["M3x20_hex_pillar", "hex", 3, 20, 5/cos(30), 5/cos(30), 6, 6, "silver", "silver", -6, 6]; +M3x20_nylon_pillar = ["M3x20_nylon_pillar", "nylon", 3, 20, 8, 5/cos(30), 0, 6, "white", "yellow", -6, 6]; +M4x17_nylon_pillar = ["M4x17_nylon_pillar", "nylon", 4, 20, 8, 5/cos(30), 0, 6, "white", "yellow", -6, 6]; +M3x20_nylon_hex_pillar = ["M3x20_nylon_hex_pillar", "nylon", 3, 20, 8/cos(30), 8/cos(30), 6, 6, grey20, grey20, -6, 6]; +M3x10_nylon_hex_pillar = ["M3x10_nylon_hex_pillar", "nylon", 3, 10,5.5/cos(30),5.5/cos(30),6, 6, grey20, grey20, -6, 6]; + + +pillars = [M2x16_brass_pillar, M3x13_hex_pillar, M3x20_hex_pillar, M3x20_nylon_pillar, M4x17_nylon_pillar, M3x10_nylon_hex_pillar, M3x20_nylon_hex_pillar]; + +use diff --git a/vitamins/psu.scad b/vitamins/psu.scad new file mode 100644 index 0000000..3920cd7 --- /dev/null +++ b/vitamins/psu.scad @@ -0,0 +1,339 @@ +// +// 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 . +// + +// +//! Powersupplies. Can be a simple cube or can be defined by a list of six faces, each with thickness, holes, cutouts, etc. +//! +//! Face order is bottom, top, left, right, front, back. +// +include <../core.scad> +use <../utils/maths.scad> +use <../utils/sector.scad> +use <../utils/round.scad> +include +use +use +use +include <../fan_guard.scad> + +function psu_face_holes(type) = type[0]; //! List of screw hole positions +function psu_face_thickness(type) = type[1]; //! The thickness +function psu_face_cutouts(type) = type[2]; //! List of polygons to remove +function psu_face_grill(type) = type[3]; //! Is this face a grill +function psu_face_fan(type) = type[4]; //! Fan x,y position and type +function psu_face_iec(type) = type[5]; //! IEC connector x,y, rotation and type +function psu_face_switch(type) = type[6]; //! Rocker switch x,y, rotation and type + +function psu_name(type) = type[1]; //! The part name +function psu_length(type) = type[2]; //! Length +function psu_width(type) = type[3]; //! Width +function psu_height(type) = type[4]; //! Height +function psu_screw(type) = type[5]; //! Screw type +function psu_screw_hole_radius(type) = type[6]; //! Clearance hole for screw, bigger than normal on ATX +function atx_psu(type) = type[7]; //! True if an ATX style PSU +function psu_left_bay(type) = type[8]; //! Bay for terminals +function psu_right_bay(type) = type[9]; //! Bay for heatsink +function psu_terminals(type) = type[10]; //! How many terminals and the y offset from the back +function psu_faces(type) = type[11]; //! List of face descriptions +function psu_accessories(type) = type[12]; //! Accessories to add to BOM, e.g. mains lead + +function terminal_block_pitch(type) = type[0]; //! Pitch between screws +function terminal_block_divider(type) = type[1]; //! Width of the dividers +function terminal_block_height(type) = type[2]; //! Height of the dividers +function terminal_block_depth(type) = type[3]; //! Total depth +function terminal_block_height2(type) = type[4]; //! Height under the contacts +function terminal_block_depth2(type) = type[5]; //! Depth of contact well + +function terminal_block_length(type, ways) = terminal_block_pitch(type) * ways + terminal_block_divider(type); //! Total length of terminal block + +module terminal_block(type, ways) { //! Draw a power supply terminal block + tl = terminal_block_length(type, ways); + depth = terminal_block_depth(type); + depth2 = terminal_block_depth2(type); + div = terminal_block_divider(type); + h = terminal_block_height(type); + h2 = terminal_block_height2(type); + pitch = terminal_block_pitch(type); + back_wall = depth - depth2; + contact_depth = depth2 - back_wall; + contact_width = pitch - div; + contact_h = 0.4; + washer_t = 1.2; + translate([0, -tl]) { + color(grey20) { + cube([depth, tl, h2]); + + translate([depth2, 0]) + cube([depth - depth2, tl, h]); + + for(i = [0 : ways]) + translate([0, i * pitch + div]) + rotate([90, 0, 0]) + linear_extrude(height = div) + hull() { + r = 2; + square([depth, eps]); + + translate([depth - eps, 0]) + square([eps, h]); + + translate([r, h - r]) + circle4n(r); + } + } + color("silver") + for(i = [0 : ways - 1]) translate([0, i * pitch + div, h2]) { + translate([back_wall, 1]) + cube([contact_depth, contact_width - 2, contact_h]); + + translate([back_wall + contact_depth / 2 - contact_width / 2, 0]) + cube([contact_width, contact_width, contact_h + washer_t]); + + translate([back_wall + contact_depth / 2, contact_width / 2, contact_h + washer_t]) + not_on_bom() no_explode() + screw(M3_pan_screw, 8); + } + } +} + +function psu_face_transform(type, face) = //! Returns a transformation matrix to get to the specified face + let(l = psu_length(type), + w = psu_width(type), + h = psu_height(type), + f = psu_faces(type)[face], + left = psu_left_bay(type), + right = psu_right_bay(type), + rotations = [[180, 0, 0], [0, 0, 0], [90, 0, -90], [90, 0, 90], [90, 0, 0], [-90, 0, 0]], + translations = [h / 2, h / 2, l / 2 - left, l / 2 - right, w / 2, w / 2] + ) translate([0, 0, h / 2]) * rotate(rotations[face]) * translate([0, 0, translations[face]]); + +grill_hole = 4.5; +grill_gap = 1.5; +module grill(width, height) { + nx = floor(width / (grill_hole + grill_gap)); + xpitch = width / nx; + ny = floor(height / ((grill_hole + grill_gap) * cos(30))); + ypitch = height / ny; + + 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; + translate([x, y]) + circle(d = grill_hole); + } +} + +module psu(type) { //! Draw a power supply + vitamin(str("psu(", type[0], "): PSU ", psu_name(type))); + + for(part = psu_accessories(type)) + vitamin(part); + + l = psu_length(type); + w = psu_width(type); + h = psu_height(type); + faces = psu_faces(type); + left = psu_left_bay(type); + right = psu_right_bay(type); + if(len(faces) < 2) + translate_z(h / 2) + color("silver") cube([l, w, h], center = true); + else { + for(i = [0 : 1 : len(faces) - 1]) { + f = faces[i]; + t = psu_face_thickness(f); + xw = [l, l - left - right, w, w, l, l - left - right][i]; + yw = [w, w, h, h, h, h][i]; + xo = [0, left / 2 - right / 2, 0, 0, 0, left / 2 - right / 2][i]; + fan = psu_face_fan(f); + iec = psu_face_iec(f); + switch = psu_face_switch(f); + + multmatrix(psu_face_transform(type, i)) + translate([xo, 0, -t]) { + color("silver") linear_extrude(height = t) + union() { + difference() { + square([xw, yw], center = true); + + cutouts = psu_face_cutouts(f); + if(cutouts) + for(cutout = cutouts) + polygon([for(p = cutout) p]); + + for(h = psu_face_holes(f)) + translate(h) + drill(screw_pilot_hole(psu_screw(type)), 0); + + if(psu_face_grill(f)) { + mx = 6; + my1 = i == f_top && psu_face_grill(faces[f_back]) ? 0 : 6; + my2 = i == f_back && psu_face_grill(faces[f_top]) ? 0 : 6; + translate([0, (my2 - my1) / 2]) + grill(xw - 2 * mx, yw - my1 - my2); + } + if(fan) + translate([fan.x, fan.y]) intersection() { + fan_holes(fan.z, h = 0); + + difference() { + square(inf, true); + + fan_guard(fan.z, thickness = 0, grill = true); + } + } + if(iec) + translate([iec.x, iec.y]) + rotate(iec.z) + iec_holes(iec[3], 0); + if(switch) + translate([switch.x, switch.y]) + rotate(switch.z) + rocker_hole(switch[3], 0); + } + } + + not_on_bom() no_explode() { + if(fan) + translate([fan.x, fan.y, -fan_depth(fan.z) / 2]) { + fan(fan.z); + + screw = alternate_screw(hs_cs_cap, fan_screw(fan.z)); + fan_hole_positions(fan.z) + translate_z(t + eps) + screw(screw, 8); + + } + + if(iec) + translate([iec.x, iec.y]) + rotate(iec.z) + iec_assembly(iec[3], t); + + if(switch) + translate([switch.x, switch.y, t]) + rotate(switch.z) + rocker(switch[3]); + } + } + } + } + // Special case for lighting type PSUs with teminals at the end + terminals = psu_terminals(type); + if(terminals) { + ft = psu_face_thickness(faces[f_front]); + bt = psu_face_thickness(faces[f_back]); + rt = psu_face_thickness(faces[f_right]); + lt = psu_face_thickness(faces[f_left]); + cutout = psu_face_cutouts(faces[f_left])[0]; + z = cutout[2].y + h / 2; + pw = w -ft - bt; + pl = l - right - rt; + pcb_thickness = 1.6; + heatsink_offset = 13.5; + color("#FCD67E") + translate([(-right - rt) / 2, (ft - bt) / 2, z - pcb_thickness]) + linear_extrude(height = pcb_thickness) + difference() { + square([pl, pw], center = true); + + translate([-pl / 2, -pw / 2]) + square(16, center = true); + } + + // earth strap + tab_w = w / 2 + cutout[2].x; + color("silver") + translate([-l / 2, w / 2 - tab_w, z]) + cube([left, tab_w - bt, lt]); + + // Earth pilar and screw + earth_inset = 4.5; + earth_d = 5; + translate([-l / 2 + earth_inset, w / 2 - tab_w / 2]) { + color("silver") + cylinder(d = earth_d, h = z - pcb_thickness); + + translate_z(z + lt) + not_on_bom() no_explode() + spring_washer(M3_washer) + screw(M3_pan_screw, 8); + } + + // terminal block + tb = terminals[2]; + if(tb) + translate([-l / 2, w / 2 - terminals.y, z]) + terminal_block(tb, terminals[0]); + + // Heatsink + // + heatsink_cutout = psu_face_cutouts(faces[f_right])[0]; + if(right && heatsink_cutout) { + z_top = heatsink_cutout[1].y + h / 2; + length = heatsink_cutout[2].x + w / 2 - 1.5; + + color("silver") + translate([l / 2, -w / 2]) + rotate([90, 0, 180]) + linear_extrude(height = length) { + translate([right + rt, z_top]) + rotate(135) + square([rt, right * sqrt(2)]); + + square([rt, z_top - right]); + + translate([rt, z_top - right]) + sector(rt, 135, 180); + } + } + } +} + +module psu_screw_positions(type, face = undef) { //! Position children at the screw positions on the preferred mounting face, which can be overridden. + faces = psu_faces(type); + f = is_undef(face) ? faces && psu_face_holes(faces[f_bottom]) ? f_bottom + : f_front + : face; + if(len(psu_faces(type)) > f) + multmatrix(psu_face_transform(type, f)) + for(point = psu_face_holes(psu_faces(type)[f])) + translate(point) + children(); +} + +module atx_psu_cutout(type) { //! Cut out for the rear of an ATX + holes = psu_face_holes(psu_faces(type)[f_front]); + translate([holes[0].x, -psu_width(type) / 2, psu_height(type) / 2 + holes[0].y]) + rotate([90, 0, 0]) + linear_extrude(height = 100, center = true) + round(5) + polygon([ // https://www.techpowerup.com/forums/threads/pc-component-dimensions.157239, tweaked + [18.7, -13], + [ 5.7, 0], + [ 5.7, 54], + [18.7, 67], + [127, 67], + [140, 67 - 13 / tan(52)], + [140, -5 + 11 / tan(52)], + [129, -5], + [81.3, -5], + [73.3, -13], + ]); +} diff --git a/vitamins/psus.scad b/vitamins/psus.scad new file mode 100644 index 0000000..f27f5e5 --- /dev/null +++ b/vitamins/psus.scad @@ -0,0 +1,104 @@ +// +// 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 . +// +include +include +include +// +// Hole positions are looking from below / outside +// +// Face order is bottom, top, left, right, front, back. +// +// Meanwell RS-150-12 +mw_terminals = [9.525, 1.5, 15, 17.8, 7, 15]; + +PD_150_12 = + ["PD_150_12", "PD-150-12", 199, 98, 38, M3_pan_screw, M3_clearance_radius, false, 11, 4.5, [7, 11, mw_terminals], + [ + [[[82.5, -40], [82.5, 40], [-37.5, -40], [-37.5, 40]], 1.5, []], + [[], 0.5, [], true], + [[], 0.5, [[[-49, -19], [-49, -11.5], [-40, -11.5], [-40, 5], [47.5, 5], [47.5, -19]]]], + [[], 1.5, [[[-49, -19], [-49, -6], [37.5, -6], [37.5, -12.5], [49, -12.5], [49, -19]]]], + [[[-77.5, 1], [79.5, 9.5], [79.5, -9.5]], 1.5, []], + [[], 0.5, [], true], + ], + [] + ]; + +st_terminals = [9.666, 2, 13, 15, 8, 13.5]; +S_250_48 = + ["S_250_48", "S-250-48", 200, 110, 50, M3_pan_screw, M3_clearance_radius, false, 13, 5, [9, 11, st_terminals], + [ + [[[-39, -45.5], [-39, 39.5], [86, -45.5], [86, 39.5]], 1.5, []], + [[], 0.5, [], true], + [[], 0.5, [[[-55, -25], [-55, -17], [-46, -17], [-46, 11], [53.5, 11], [53.5, -25]]]], + [[], 1.5, [[[-55, -25], [-55, -13], [43.5, -13], [43.5, -15], [55, -15], [55, -25]]]], + [[[-79.5, 0], [78.5, 12.5], [78.5, -12.5]], 1.5, []], + [[], 0.5, [], true], + ], + [] + ]; + +// Single fan at back, wires exit opposite side from mains in +ATX500 = + ["ATX500", "ATX500", 150, 140, 86, No632_pan_screw, 5/2, true, 0, 0, [], + [ + [[], 0.8, []], + [[], 0.8, []], + [[], 0.8, []], + [[], 0.8, []], + [[[-69, -27], [-69, 37], [69, 37], [45, -37]], 0.8, [], false, [-25, 0, fan80x25], [45, -19.6, 180, IEC_inlet_atx], [45, 23, 90, small_rocker]], + [[], 0.8, [], true], + ], + [": IEC mains lead"] + ]; + +KY240W = + ["KY240W", "KY-240W-12-L", 199, 110, 50, M3_cap_screw, M3_clearance_radius, false, 0, 0, [], + [ + [[[ 199 / 2 - 12, 110 / 2 - 93], + [ 199 / 2 - 12, 110 / 2 - 9 ], + [ 199 / 2 - 138, 110 / 2 - 93], + [ 199 / 2 - 138, 110 / 2 - 9 ]]] + + ], + [] + ]; + +// This PSU, and ones very like it, are sold by LulzBot, and various sellers on eBay. +// The screw layout specified here uses the inner set of screw-mounts on the PSU, which are M4. +// The outer set don't appear to be M3, even though the datasheet claims they are. +S_300_12 = + ["S_300_12", "S-300-12", 215, 115, 50, M4_cap_screw, M4_clearance_radius, false, 0, 0, [], + [ [[[ 215 / 2 - 32.5, 115 / 2 - 82.5], + [ 215 / 2 - 32.5, 115 / 2 - 32.5], + [ 215 / 2 - 182.5, 115 / 2 - 82.5], + [ 215 / 2 - 182.5, 115 / 2 - 32.5]]] + ], + [] + ]; + +External = + ["External", "X Box", 0, 0, 0, false, false, false, 0, 0, [], + [], + [": IEC mains lead"] + ]; + +psus = [PD_150_12, S_250_48, ATX500, KY240W, S_300_12]; + +use diff --git a/vitamins/pulley.scad b/vitamins/pulley.scad new file mode 100644 index 0000000..32caa89 --- /dev/null +++ b/vitamins/pulley.scad @@ -0,0 +1,143 @@ +// +// 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 . +// + +// +//! Timing belt pulleys, both toothed and plain with internal bearings for idlers. +// +include <../core.scad> + +use +use +use <../utils/round.scad> + +function pulley_type(type) = type[1]; //! Part description +function pulley_teeth(type) = type[2]; //! Number of teeth +function pulley_od(type) = type[3]; //! Outer diameter +function pulley_belt(type) = type[4]; //! Belt type +function pulley_width(type) = type[5]; //! Width of teeth / belt channel +function pulley_hub_dia(type) = type[6]; //! Hub diameter +function pulley_hub_length(type) = type[7]; //! Hub length +function pulley_bore(type) = type[8]; //! Bore diameter for shaft +function pulley_flange_dia(type) = type[9]; //! Flange diameter +function pulley_flange_thickness(type) = type[10]; //! Flange thickness +function pulley_screw_length(type) = type[11]; //! Grup screw length +function pulley_screw_z(type) = type[12]; //! Grub screw position +function pulley_screw(type) = type[13]; //! Grub screw type +function pulley_screws(type) = type[14]; //! Number of grub screws + +function pulley_ir(type) = pulley_od(type) / 2 - (pulley_teeth(type) ? belt_tooth_height(pulley_belt(type)) : 0); //! Inside radius of the teeth +function pulley_pr(type) = let(belt = pulley_belt(type)) //! Pitch radius + pulley_teeth(type) ? pulley_teeth(type) * belt_pitch(belt) / 2 / PI + : pulley_ir(type) + belt_thickness(belt) - belt_pitch_height(belt); + +function pulley_offset(type) = -pulley_hub_length(type) - pulley_flange_thickness(type) - pulley_width(type) / 2; //! Offset of the belt path centre +function pulley_height(type) = pulley_hub_length(type) + 2 * pulley_flange_thickness(type) + pulley_width(type); //! Total height of pulley +function pulley_extent(type) = max(pulley_flange_dia(type), pulley_hub_dia(type)) / 2; //! Largest diameter + +T_angle = 40; +GT_r = 0.555; + +module pulley(type) { //! Draw a pulley + teeth = pulley_teeth(type); + + vitamin(str("pulley(", type[0], "): Pulley ", pulley_type(type), pulley_screws(type) ? " " : " idler ", teeth ? str(teeth, " teeth") : "smooth")); + + ft = pulley_flange_thickness(type); + tw = pulley_od(type) * PI / (teeth * 2); + hl = pulley_hub_length(type); + w = pulley_width(type); + r1 = pulley_bore(type) / 2; + + or = pulley_od(type) / 2; + ir = pulley_ir(type); + module core() { + translate_z(pulley_hub_length(type) + ft) + linear_extrude(height = w) let($fa = 1, $fs = 0.1) + difference() { + circle(or); + + circle(r1); + + for(i = [0 : 1 : teeth - 1]) + rotate(i * 360 / teeth) + if(pulley_type(type)[0] == "G") + translate([0, ir + GT_r]) + hull() { + circle(GT_r); + + translate([0, GT_r]) + square(2 * GT_r, center = true); + } + else + translate([0, (ir + or) / 2]) + hull() { + for(side = [-1, 1]) + translate([side * tw / 2, 0]) + rotate(-side * T_angle / 2) + square([eps, (or - ir)], center = true); + + translate([0, 1]) + square([tw, eps], center = true); + } + + } + } + + module screw_holes() { + if(pulley_screws(type)) + translate_z(pulley_screw_z(type)) + for(i = [0 : pulley_screws(type) - 1]) + rotate([-90, 0, i * -90]) + cylinder(r = screw_radius(pulley_screw(type)), h = 100); + } + + color("silver") { + render() difference() { + rotate_extrude() translate([r1, 0]) { + if(hl) + square([pulley_hub_dia(type) / 2 - r1, hl]); + + for(z = [pulley_hub_length(type), hl + ft + w]) + translate([0, z]) + square([pulley_flange_dia(type) / 2 - r1, ft]); + } + if(pulley_screw_z(type) < hl) + screw_holes(); + } + render() difference() { // T5 pulleys have screw through the teeth + core(); + + if(pulley_screw_z(type) > hl) + screw_holes(); + } + } +} + +module pulley_assembly(type) { //! Draw a pulley with its grub screws in place + translate_z(pulley_offset(type)) { + pulley(type); + + if(pulley_screws(type)) + translate_z(pulley_screw_z(type)) + for(i = [0 : pulley_screws(type) - 1]) + rotate([-90, 0, i * -90]) + translate_z(pulley_bore(type) / 2 + pulley_screw_length(type)) + screw(pulley_screw(type), pulley_screw_length(type)); + } +} diff --git a/vitamins/pulleys.scad b/vitamins/pulleys.scad new file mode 100644 index 0000000..74ff954 --- /dev/null +++ b/vitamins/pulleys.scad @@ -0,0 +1,50 @@ +// +// 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 . +// + +// +// n t o b w h h b f f s s s s +// a e d e i u u o l l c c c c +// m e l d b b r a a r r r r +// e t t t e n n e e e e +// h h d l g g w w w w +// e e s +// l z +// d t +// +T5x10_pulley = ["T5x10_pulley", "T5", 10, 15, T5x6, 11.6, 7.9, 7, 5, 19.3, 1.7, 3, 10.7, M3_grub_screw, 1]; +T2p5x16_pulley = ["T2p5x16_pulley", "T2.5", 16, 12.16, T2p5x6, 8, 16, 5.7, 5, 16.0, 1.0, 6, 3.75, M4_grub_screw, 1]; +GT2x20um_pulley = ["GT2x20um_pulley", "GT2UM", 20, 12.22, GT2x6, 7.5, 18, 6.5, 5, 18.0, 1.0, 6, 3.75, M3_grub_screw, 2]; +GT2x20ob_pulley = ["GT2x20ob_pulley", "GT2OB", 20, 12.22, GT2x6, 7.5, 16, 5.5, 5, 16.0, 1.0, 6, 3.25, M3_grub_screw, 2]; +GT2x12_pulley = ["GT2x12_pulley", "GT2RD", 12, 7.15, GT2x6, 6.5, 12, 5.5, 4, 12.0, 1.0, 4, 3.0, M3_grub_screw, 2]; +GT2x20_toothed_idler = ["GT2x20_toothed_idler", "GT2", 20, 12.22, GT2x6, 6.5, 18, 0, 4, 18.0, 1.0, 0, 0, false, 0]; +GT2x20_plain_idler = ["GT2x20_plain_idler", "GT2", 0, 12.0, GT2x6, 6.5, 18, 0, 4, 18.0, 1.0, 0, 0, false, 0]; +GT2x16_toothed_idler = ["GT2x16_toothed_idler", "GT2", 16, 9.75, GT2x6, 6.5, 14, 0, 3, 14.0, 1.0, 0, 0, false, 0]; +GT2x16_plain_idler = ["GT2x16_plain_idler", "GT2", 0, 9.63, GT2x6, 7.0, 13, 0, 3, 13.0, 1.0, 0, 0, false, 0]; + +pulleys = [T5x10_pulley, + T2p5x16_pulley, + GT2x20um_pulley, + GT2x20ob_pulley, + GT2x12_pulley, + GT2x20_toothed_idler, + GT2x20_plain_idler, + GT2x16_toothed_idler, + GT2x16_plain_idler]; + +use diff --git a/vitamins/rail.scad b/vitamins/rail.scad new file mode 100644 index 0000000..de75c28 --- /dev/null +++ b/vitamins/rail.scad @@ -0,0 +1,165 @@ +// +// 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 . + +// +//! Linear rails with carriages. +// +include <../core.scad> + +use + +function rail_width(type) = type[1]; //! Width of rail section +function rail_height(type) = type[2]; //! Height of rail section +function rail_end(type) = type[3]; //! Minimum distance screw can be from the end +function rail_pitch(type) = type[4]; //! Distance between screws +function rail_bore(type) = type[5]; //! Counter bore diameter for screw head +function rail_hole(type) = type[6]; //! Screw hole diameter +function rail_bore_depth(type) = type[7]; //! Counter bore depth +function rail_screw(type) = type[8]; //! Screw type +function rail_carriage(type) = type[9]; //! Carriage type +function rail_end_screw(type) = type[10]; //! Screw used for ends only (Countersink used for better location) +function rail_screw_height(type, screw) = rail_height(type) - rail_bore_depth(type) + screw_head_depth(screw, rail_hole(type)); //! Position screw taking into account countersink into counterbored hole +function rail_travel(type, length) = length - carriage_length(rail_carriage(type)); //! How far the carriage can travel + +function carriage_length(type) = type[0]; //! Overall length +function carriage_block_length(type) = type[1]; //! Length of the metal part +function carriage_width(type) = type[2]; //! Width of carriage +function carriage_height(type) = type[3]; //! Height of carriage +function carriage_clearance(type) = type[4]; //! Gap under the carriage +function carriage_pitch_x(type) = type[5]; //! Screw hole x pitch +function carriage_pitch_y(type) = type[6]; //! Screw hole y pitch +function carriage_screw(type) = type[7]; //! Carriage screw type +function carriage_screw_depth(type) = 2 * screw_radius(carriage_screw(type)); //! Carriage thread depth + +module rail_hole_positions(type, length, first = 0, screws = 100, both_ends = true) { //! Position children over screw holes + pitch = rail_pitch(type); + holes = floor((length - 2 * rail_end(type)) / pitch) + 1; + for(i = [first : holes - 1 - first]) + if(i < screws || (holes - i <= screws && both_ends)) + translate([i * pitch - length / 2 + (length - (holes -1) * pitch) / 2, 0, 0]) + children(); +} + +module carriage_hole_positions(type) { //! Position children over screw holes + x_pitch = carriage_pitch_x(type); + y_pitch = carriage_pitch_y(type); + + for(x = [-1, 1], y = [-1, 1]) + if(x < 0 || x_pitch) + translate([x * x_pitch / 2, y * y_pitch / 2, carriage_height(type)]) + children(); +} + +module carriage(type, rail) { //! Draw the specified carriage + total_l = carriage_length(type); + block_l = carriage_block_length(type); + block_w = carriage_width(type); + block_h = carriage_height(type) - carriage_clearance(type); + end_w = block_w - 0.6; + end_h = block_h - 0.3; + end_l = (total_l - block_l)/ 2; + screw = carriage_screw(type); + screw_depth = carriage_screw_depth(type); + + module cutout() { + w = rail_width(rail) + 0.4; + translate([-w / 2, 0]) + square([w , rail_height(rail) + 0.2]); + } + + color(grey90) { + rotate([90, 0, 90]) + linear_extrude(height = block_l, center = true) + difference() { + translate([-block_w / 2, carriage_clearance(type)]) + square([block_w, block_h - screw_depth]); + + cutout(); + } + + translate_z(carriage_height(type) - screw_depth) + linear_extrude(height = screw_depth) + difference() { + square([block_l, block_w], center = true); + + carriage_hole_positions(type) + circle(screw_pilot_hole(screw)); + } + + } + color(grey20) + for(end = [-1, 1]) + translate([end * (block_l / 2 + end_l / 2), 0]) + rotate([90, 0, 90]) + linear_extrude(height = end_l, center = true) + difference() { + translate([-end_w / 2, carriage_clearance(type)]) + square([end_w, end_h]); + + cutout(); + } +} + +module rail(type, length) { //! Draw the specified rail + width = rail_width(type); + height = rail_height(type); + + vitamin(str("rail(", type[0], ", ", length, "): Linear rail ", type[0], " x ", length, "mm")); + + color(grey90) { + linear_extrude(height = height - rail_bore_depth(type)) difference() { + square([length, width], center = true); + + rail_hole_positions(type, length) + circle(d = rail_hole(type)); + } + + translate_z(rail_height(type) - rail_bore_depth(type)) + linear_extrude(height = rail_bore_depth(type)) difference() { + square([length, width], center = true); + + rail_hole_positions(type, length) + circle(d = rail_bore(type)); + } + } +} + +module rail_assembly(type, length, pos) { //! Rail and carriage assembly + rail(type, length); + + translate([pos, 0]) + carriage(rail_carriage(type), type); + +} + +module rail_screws(type, length, thickness, screws = 100) { //! Place screws in the rail + screw = rail_screw(type); + end_screw = rail_end_screw(type); + screw_len = screw_longer_than(rail_screw_height(type, screw) + thickness); + end_screw_len = screw_longer_than(rail_screw_height(type, end_screw) + thickness); + + index_screws = screws > 2 ? 1 : 2; + + translate_z(rail_screw_height(type, end_screw)) + rail_hole_positions(type, length, 0, index_screws) + screw(end_screw, end_screw_len); + + translate_z(rail_screw_height(type, screw)) + rail_hole_positions(type, length, index_screws, screws) + screw(screw, screw_len); +} diff --git a/vitamins/rails.scad b/vitamins/rails.scad new file mode 100644 index 0000000..1d82e75 --- /dev/null +++ b/vitamins/rails.scad @@ -0,0 +1,44 @@ +// +// 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 . +// + +// +// Carriages +// +// L L1 W H H1 C B +MGN5_carriage = [ 16, 9.6, 12, 6, 1.5, 0, 8 , M2_cap_screw ]; +MGN7_carriage = [ 23, 14.3, 17, 8, 1.5, 8, 12, M2_cap_screw ]; +MGN9_carriage = [ 29.7, 20.8, 20, 10, 2, 10, 15, M3_cap_screw ]; +MGN12_carriage = [ 34.7, 21.7, 27, 13, 3, 15, 20, M3_cap_screw ]; +MGN15_carriage = [ 43.3, 27.7, 32, 16, 4, 20, 25, M3_cap_screw ]; +SSR15_carriage = [ 40.3, 23.3, 34, 24, 4.5, 0, 26, M4_cap_screw ]; +// +// Rails +// +// +// Wr Hr E P D d h +MGN5 = [ "MGN5", 5, 3.6, 5, 15, 3.5, 2.4, 0.8, M2_cs_cap_screw, MGN5_carriage, M2_cs_cap_screw ]; // Screw holes too small for M2 heads +MGN7 = [ "MGN7", 7, 5, 5, 15, 4.3, 2.4, 2.6, M2_cap_screw, MGN7_carriage, M2_cs_cap_screw ]; +MGN9 = [ "MGN9", 9, 6, 7.5, 20, 6.0, 3.5, 3.5, M3_cap_screw, MGN9_carriage, M3_cs_cap_screw ]; +MGN12= [ "MGN12", 12, 8, 10, 25, 6.0, 3.5, 4.5, M3_cap_screw, MGN12_carriage, M3_cs_cap_screw ]; +MGN15= [ "MGN15", 15, 10, 10, 40, 6.0, 3.5, 5.0, M3_cap_screw, MGN15_carriage, M3_cs_cap_screw ]; +SSR15= [ "SSR15", 15, 12.5,10, 60, 7.5, 4.5, 5.3, M4_cap_screw, SSR15_carriage, M4_cs_cap_screw ]; + +rails = [MGN5, MGN7, MGN9, MGN15, SSR15]; + +use diff --git a/vitamins/ring_terminal.scad b/vitamins/ring_terminal.scad new file mode 100644 index 0000000..058c391 --- /dev/null +++ b/vitamins/ring_terminal.scad @@ -0,0 +1,98 @@ +// +// 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 . +// + +// +//! Ring terminals and earth assemblies for DiBond panels. +// +include <../core.scad> +use +use +use +use <../utils/tube.scad> + +function ringterm_od(type) = type[1]; //! Outside diameter +function ringterm_id(type) = type[2]; //! Inside diameter +function ringterm_length(type) = type[3]; //! Length of the tail including the ring +function ringterm_width(type) = type[4]; //! Width of the tail +function ringterm_hole(type) = type[5]; //! Wire hole diameter +function ringterm_thickness(type) = type[6]; //! Metal thickness +function ringterm_screw(type) = type[7]; //! Screw type +function ringterm_extent(type) = ringterm_length(type) / sqrt(2); //! Space to leave + +module ring_terminal(type) { //! Draw specifeid ring terminal + screw = ringterm_screw(type); + d = 2 * screw_radius(screw); + vitamin(str("ring_terminal(", type[0], "): Ring terminal ",d,"mm")); + + t = ringterm_thickness(type); + w = ringterm_width(type); + od = ringterm_od(type); + id = ringterm_id(type); + l = ringterm_length(type); + angle = 45; + bend = washer_radius(screw_washer(screw)) + t * tan(angle / 2); + color("silver") union() { + tube(or = od / 2, ir = id / 2, h = t, center = false); + + translate([-w / 2, -bend, 0]) + cube([w, bend - id / 2, t]); + + translate([0, -bend]) + rotate([-angle, 0, 0]) + linear_extrude(height = t) + difference() { + length = l - od / 2 - bend; + hull() { + translate([-w / 2, -eps]) + square([w, eps]); + + translate([0, -length + w / 2]) + circle(d = w); + } + translate([0, -length + w / 2]) + circle(d = ringterm_hole(type)); + } + } + translate_z(ringterm_thickness(type)) + children(); +} + +module ring_terminal_hole(type, h = 0) //! Drill hole for the screw + drill(screw_clearance_radius(ringterm_screw(type)), h); + +module ring_terminal_assembly(type, thickness, top = false) { //! Earthing assembly for DiBond twin skins + screw = ringterm_screw(type); + washer = screw_washer(screw); + nut = screw_nut(screw); + screw_length = screw_longer_than(thickness + 2 * washer_thickness(washer) + nut_thickness(nut, true) + ringterm_thickness(type)); + + explode(10, true) star_washer(washer) + if(top) + ring_terminal(type) screw(screw, screw_length); + else + screw(screw, screw_length); + + vflip() + translate_z(thickness) + explode(10, true) star_washer(washer) + if(!top) + explode(10,true) ring_terminal(type) nut(nut, true); + else + nut(nut, true); +} diff --git a/vitamins/ring_terminals.scad b/vitamins/ring_terminals.scad new file mode 100644 index 0000000..f63aeaf --- /dev/null +++ b/vitamins/ring_terminals.scad @@ -0,0 +1,34 @@ +// +// 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 . +// + +// +// Ring terminals +// +// o i l w h t s +// d d e i o h c +// n d l i r +// g t e c e +// t h k w +// h +// +M3_ringterm = ["M3_ringterm", 6, 3, 12, 3, 1.5, 0.2, M3_dome_screw]; + +ring_terminals = [M3_ringterm]; + +use diff --git a/vitamins/rocker.scad b/vitamins/rocker.scad new file mode 100644 index 0000000..e11f43c --- /dev/null +++ b/vitamins/rocker.scad @@ -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 . +// + +// +//! Rocket switch. Also used for neon indicator in the same form factor. +// +include <../core.scad> +use + +function rocker_part(type) = type[1]; //! Part description +function rocker_slot_w(type) = type[2]; //! Panel slot width +function rocker_slot_h(type) = type[3]; //! Panel slow height +function rocker_flange_w(type) = type[4]; //! Flange width +function rocker_flange_h(type) = type[5]; //! Flange height +function rocker_flange_t(type) = type[6]; //! Flange thickness +function rocker_width(type) = type[7]; //! Body width +function rocker_height(type) = type[8]; //! Body height +function rocker_depth(type) = type[9]; //! Body depth +function rocker_bezel(type) = type[10]; //! Bezel width +function rocker_pivot(type) = type[11]; //! Pivot distance from the back of the flange +function rocker_button(type) = type[12]; //! How far the button extends from the bezel +function rocker_spades(type) = type[13]; //! Spade types and positions + +module rocker(type) { //! Draw the specified rocker switch + vitamin(str("rocker(", type[0], "): ", rocker_part(type))); + + bezel = rocker_bezel(type); + clearance = 0.2; + rocker_w = rocker_flange_w(type) - 2 * bezel - clearance; + rocker_h = rocker_flange_h(type) - 2 * bezel - clearance; + rocker_r = sqrt(sqr(rocker_h / 2) + sqr(rocker_flange_t(type) - rocker_pivot(type))); + y = rocker_button(type) + rocker_flange_t(type) - rocker_pivot(type); + x = sqrt(sqr(rocker_r) - sqr(y)); + + x2 = rocker_h /2 + x; + y2 = rocker_button(type); + rocker_r2 = (sqr(x2) + sqr(y2)) / (2 * y2); + + explode(30) { + color(grey20) { + linear_extrude(height = rocker_flange_t(type)) + difference() { + rounded_square([rocker_flange_w(type), rocker_flange_h(type)], 0.5); + + square([rocker_w + clearance, rocker_h + clearance], center = true); + } + + translate_z(-rocker_depth(type)) + rounded_rectangle([rocker_width(type), rocker_height(type), rocker_depth(type) + eps], 0.5, center = false); + } + if(rocker_pivot(type)) + color(grey30) + translate_z(rocker_pivot(type)) + rotate([90, 0, 90]) + linear_extrude(height = rocker_w, center = true) + difference() { + circle(rocker_r, $fa = 1); + + translate([rocker_h / 2, rocker_flange_t(type) + rocker_r2 - rocker_pivot(type)]) + circle(rocker_r2, $fa = 1); + + } + + else + color("red") cube([rocker_w, rocker_h, 2 * (rocker_flange_t(type) + rocker_button(type))], center = true); + + for(spade = rocker_spades(type)) + translate([spade[2], spade[3], -rocker_depth(type)]) + rotate([180, 0, spade[4]]) + spade(spade[0], spade[1]); + } +} + +module rocker_hole(type, h = 0) //! Make a hole to accept a rocker switch, by default 2D, set h for 3D + extrude_if(h) + rounded_square([rocker_slot_w(type), rocker_slot_h(type)], 1, center = true); diff --git a/vitamins/rockers.scad b/vitamins/rockers.scad new file mode 100644 index 0000000..b333733 --- /dev/null +++ b/vitamins/rockers.scad @@ -0,0 +1,43 @@ +// +// 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 . +// + +include + +small_spades = [[spade4p8, 7.6, 0, 0, 0], + [spade4p8, 7.6, 0, 7.1, 0]]; + +neon_spades = [[spade4p8, 7.3, 0, -7, 0], + [spade4p8, 7.3, 0, 7, 0]]; + +// +// p s s f f f w h d b p b +// a l l l l l i e e e i u +// r o o a a a d i p z v t +// t t t n n n t g t e o t +// g g g h h h l t o +// w h e e e t n +// +// w h t +// +small_rocker = ["small_rocker", "Rocker Switch PRASA1-16F-BB0BW", 13, 19.8, 15, 21, 2, 12.8, 18.5, 11.8, 2.5, -1, 3.8, small_spades]; +neon_indicator = ["neon_indicator", "Neon Indicator H8630FBNAL", 13, 19.8, 15, 21, 2, 12.8, 18.5, 12.5, 2.5, 0, 0.3, neon_spades]; + +rockers = [small_rocker, neon_indicator]; + +use diff --git a/vitamins/rod.scad b/vitamins/rod.scad new file mode 100644 index 0000000..eb4fba5 --- /dev/null +++ b/vitamins/rod.scad @@ -0,0 +1,37 @@ +// +// 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 . +// + +// +//! Steel rods, with optional chamfer. +// +include <../core.scad> + +rod_colour = grey80; + +module rod(d , l) { + vitamin(str("rod(", d, ", ", l, "): Smooth rod ", d, "mm x ", l, "mm")); + + chamfer = d / 10; + color(rod_colour) + hull() { + cylinder(d = d, h = l - 2 * chamfer, center = true); + + cylinder(d = d - 2 * chamfer, h = l, center = true); + } +} diff --git a/vitamins/screw.scad b/vitamins/screw.scad new file mode 100644 index 0000000..1ddc206 --- /dev/null +++ b/vitamins/screw.scad @@ -0,0 +1,257 @@ +// +// 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 . +// + +// +//! Machine screws and wood screws with various head styles. +// +include <../core.scad> + +use +use <../utils/rounded_cylinder.scad> + +function screw_head_type(type) = type[2]; //! Head style hs_cap, hs_pan, hs_cs, hs_hex, hs_grub, hs_cs_cap, hs_dome +function screw_radius(type) = type[3] / 2; //! Nominal radius +function screw_head_radius(type) = type[4] / 2; //! Head radius +function screw_head_height(type) = type[5]; //! Head height +function screw_socket_depth(type) = type[6]; //! Socket or slot depth +function screw_socket_af(type) = type[7]; //! Socket across flats +function screw_max_thread(type) = type[8]; //! Maximum thread length +function screw_washer(type) = type[9]; //! Default washer +function screw_nut(type) = type[10]; //! Default nut +function screw_pilot_hole(type) = type[11]; //! Pilot hole radius for wood screws, tap radius for machine screws +function screw_clearance_radius(type) = type[12]; //! Clearance hole radius +function screw_nut_radius(type) = screw_nut(type) ? nut_radius(screw_nut(type)) : 0; //! Radius of matching nut +function screw_boss_diameter(type) = max(washer_diameter(screw_washer(type)) + 1, 2 * (screw_nut_radius(type) + 3 * extrusion_width)); //! Boss big enough for nut trap and washer +function screw_head_depth(type, d) = screw_head_height(type) ? 0 : screw_head_radius(type) - d / 2; //! How far a counter sink head will go into a straight hole diameter d + +function screw_longer_than(x) = x <= 5 ? 5 : //! Returns shortest screw length longer or equal to x + x <= 8 ? 8 : + x <= 10 ? 10 : + x <= 12 ? 12 : + x <= 16 ? 16 : + ceil(x / 5) * 5; + +function screw_shorter_than(x) = x >= 20 ? floor(x / 5) * 5 : //! Returns longest screw length shorter than or equal to x + x >= 16 ? 16 : + x >= 12 ? 12 : + x >= 10 ? 10 : + x >= 8 ? 8 : + x >= 6 ? 6 : + 5; + +function screw_smaller_than(d) = d >= 2.5 && d < 3 ? 2.5 : floor(d); // Largest diameter screw less than or equal to specified diameter + +module screw(type, length, hob_point = 0, nylon = false) { //! Draw specified screw, optionally hobbed or nylon + description = str("Screw ", nylon ? "Nylon " : "", type[1], " x ", length, "mm", hob_point ? str(", hobbed at ", hob_point) : ""); + vitamin(str("screw(", type[0], "_screw, ", length, arg(hob_point, 0, "hob_point"), arg(nylon, false, "nylon"), "): ", description)); + + head_type = screw_head_type(type); + rad = screw_radius(type) - eps; + head_rad = screw_head_radius(type); + head_height = screw_head_height(type); + socket_af = screw_socket_af(type); + socket_depth= screw_socket_depth(type); + socket_rad = socket_af / cos(30) / 2; + max_thread = screw_max_thread(type); + thread = max_thread ? min(length, max_thread) : length; + shank = length - thread; + colour = nylon || head_type == hs_grub ? grey40 : grey80; + + + module shaft(headless = 0) { + point = screw_nut(type) ? 0 : 3 * rad; + color(colour * 0.9 ) + rotate_extrude() { + translate([0, -length + point]) + square([rad, length - headless - point]); + + if(point) + polygon([ + [0, -length], [0, point - length], [rad - 0.1, point - length] + ]); + } + if(shank >= 5) + color(colour) + translate_z(-shank) + cylinder(r = rad + eps, h = shank - headless); + + } + + explode(length + 10) { + if(head_type == hs_cap) { + color(colour) { + cylinder(r = head_rad, h = head_height - socket_depth); + + translate_z(head_height - socket_depth) + linear_extrude(height = socket_depth) + difference() { + circle(head_rad); + circle(socket_rad, $fn = 6); + } + + } + shaft(); + } + if(head_type == hs_grub) { + color(colour) { + translate_z(-socket_depth) + linear_extrude(height = socket_depth) + difference() { + circle(r = rad); + circle(socket_rad, $fn = 6); + } + + shaft(socket_depth); + } + } + if(head_type == hs_hex) { + color(colour) + cylinder(r = head_rad, h = head_height, $fn = 6); + + shaft(); + } + if(head_type == hs_pan) { + socket_rad = 0.6 * head_rad; + socket_depth = 0.5 * head_height; + socket_width = 1; + color(colour) { + rotate_extrude() + difference() { + rounded_corner(r = head_rad, h = head_height, r2 = head_height / 2); + + translate([0, head_height - socket_depth]) + square([socket_rad, 10]); + } + + linear_extrude(height = head_height) + difference() { + circle(socket_rad + eps); + + square([2 * socket_rad, socket_width], center = true); + square([socket_width, 2 * socket_rad], center = true); + } + } + shaft(); + } + + if(head_type == hs_dome) { + lift = 0.38; + color(colour) { + rotate_extrude() { + difference() { + intersection() { + translate([0, -head_height + lift]) + circle(2 * head_height); + + square([head_rad, head_height]); + } + translate([0, head_height - socket_depth]) + square([socket_rad, 10]); + } + } + linear_extrude(height = head_height) + difference() { + circle(socket_rad + eps); + circle(socket_rad, $fn = 6); + } + } + shaft(); + } + + if(head_type == hs_cs) { + head_height = head_rad; + socket_rad = 0.6 * head_rad; + socket_depth = 0.3 * head_rad; + socket_width = 1; + color(colour) { + rotate_extrude() + difference() { + polygon([[0, 0], [head_rad, 0], [0, -head_height]]); + + translate([0, -socket_depth + eps]) + square([socket_rad + 0.1, 10]); + } + + translate_z(-socket_depth) + linear_extrude(height = socket_depth) + difference() { + circle(socket_rad + 0.1); + + square([2 * socket_rad, socket_width], center = true); + square([socket_width, 2 * socket_rad], center = true); + } + } + shaft(socket_depth); + } + + if(head_type == hs_cs_cap) { + head_height = head_rad; + color(colour) { + rotate_extrude() + difference() { + polygon([[0, 0], [head_rad, 0], [0, -head_height]]); + + translate([0, -socket_depth + eps]) + square([socket_rad, 10]); + } + + translate_z(-socket_depth) + linear_extrude(height = socket_depth) + difference() { + circle(socket_rad + 0.1); + + circle(socket_rad, $fn = 6); + } + } + shaft(socket_depth); + } + } +} + +module screw_countersink(type) { //! Countersink shape + head_type = screw_head_type(type); + head_rad = screw_head_radius(type); + head_height = head_rad; + + if(head_type == hs_cs || head_type == hs_cs_cap) + translate_z(-head_height) + cylinder(h = head_height, r1 = 0, r2 = head_rad); +} + +module screw_and_washer(type, length, star = false, penny = false) { //! Screw with a washer which can be standard or penny and an optional star washer on top + washer = screw_washer(type); + + translate_z(exploded() * 6) + if(penny) + penny_washer(washer); + else + washer(washer); + + translate_z(washer_thickness(washer)) { + if(star) { + translate_z(exploded() * 8) + star_washer(washer); + + translate_z(washer_thickness(washer)) + screw(type, length); + } + else + screw(type, length); + } +} diff --git a/vitamins/screws.scad b/vitamins/screws.scad new file mode 100644 index 0000000..0f69022 --- /dev/null +++ b/vitamins/screws.scad @@ -0,0 +1,131 @@ +// +// 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 . +// + +// +// Screws +// +include +include + +No2_pilot_radius = 1.7 / 2; // self tapper into ABS +No4_pilot_radius = 2.0 / 2; // wood screw into soft wood +No6_pilot_radius = 2.0 / 2; // wood screw into soft wood +No8_pilot_radius = 2.5 / 2; + +No2_clearance_radius = 2.5 / 2; +No4_clearance_radius = 3.5 / 2; +No6_clearance_radius = 4.0 / 2; +No8_clearance_radius = 4.5 / 2; + +M2_tap_radius = 1.6 / 2; +M2_clearance_radius = 2.4 / 2; + +M2p5_tap_radius = 2.05 / 2; +M2p5_clearance_radius= 2.8 / 2; // M2.5 + +M3_tap_radius = 2.5 / 2; +M3_clearance_radius = 3.3 / 2; + +M4_tap_radius = 3.3 / 2; +M4_clearance_radius = 2.2; + +M5_tap_radius = 4.2 / 2; +M5_clearance_radius = 5.3 / 2; + +M6_tap_radius = 5 / 2; +M6_clearance_radius = 6.4 / 2; + +M8_tap_radius = 6.75 / 2; +M8_clearance_radius = 8.4 / 2; + +// d h d h h s s m +// e e i e e o o a +// s a a a a c c x +// c d m d d k k +// r e e e t +// i t t d h t t h +// p y e i e r +// t p r a i d a e +// i e m g e f a +// o e h p d +// n t t t +// e h +// r +// +M2_cap_screw = ["M2_cap", "M2 cap", hs_cap, 2, 3.8, 2, 1.0, 1.5, 16, M2_washer, M2_nut, M2_tap_radius, M2_clearance_radius]; +M2p5_cap_screw = ["M2p5_cap", "M2.5 cap", hs_cap, 2.5, 4.5, 2.5, 1.1, 2.0, 17,M2p5_washer, M2p5_nut, M2p5_tap_radius, M2p5_clearance_radius]; +M3_cap_screw = ["M3_cap", "M3 cap", hs_cap, 3, 5.5, 3, 1.3, 2.5, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; +M4_cap_screw = ["M4_cap", "M4 cap", hs_cap, 4, 7.0, 4, 2.0, 3.0, 20, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius]; +M5_cap_screw = ["M5_cap", "M5 cap", hs_cap, 5, 8.5, 5, 2.5, 4.0, 22, M5_washer, M5_nut, M5_tap_radius, M5_clearance_radius]; +M6_cap_screw = ["M6_cap", "M6 cap", hs_cap, 6, 10, 6, 3.3, 5.0, 24, M6_washer, M6_nut, M6_tap_radius, M6_clearance_radius]; +M8_cap_screw = ["M8_cap", "M8 cap", hs_cap, 8, 13, 8, 4.3, 6.0, 28, M8_washer, M8_nut, M8_tap_radius, M8_clearance_radius]; + +M2_cs_cap_screw = ["M2_cs_cap","M2 cs cap", hs_cs_cap,2, 3.8, 0, 0.65,1.27,16, M2_washer, M2_nut, M2_tap_radius, M2_clearance_radius]; +M3_cs_cap_screw = ["M3_cs_cap","M3 cs cap", hs_cs_cap,3, 6.0, 0, 1.05,2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; +M4_cs_cap_screw = ["M4_cs_cap","M4 cs cap", hs_cs_cap,4, 8.0, 0, 1.49,2.5, 20, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius]; + +M3_dome_screw = ["M3_dome", "M3 dome", hs_dome, 3, 5.7, 1.65, 1.04,2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; +M4_dome_screw = ["M4_dome", "M4 dome", hs_dome, 4, 7.6, 2.2, 1.3, 2.5, 20, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius]; + +M2p5_pan_screw = ["M2p5_pan", "M2.5 pan", hs_pan, 2.5, 4.7, 1.7, 0, 0, 0, M2p5_washer, M2p5_nut, M2p5_tap_radius, M2p5_clearance_radius]; +M3_pan_screw = ["M3_pan", "M3 pan", hs_pan, 3, 5.4, 2.0, 0, 0, 0, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; +M4_pan_screw = ["M4_pan", "M4 pan", hs_pan, 4, 7.8, 3.3, 0, 0, 0, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius]; +M5_pan_screw = ["M5_pan", "M5 pan", hs_pan, 5, 10, 3.95, 0, 0, 0, M5_washer, M5_nut, M5_tap_radius, M5_clearance_radius]; +M6_pan_screw = ["M6_pan", "M6 pan", hs_pan, 6, 12, 4.75, 0, 0, 0, M6_washer, M6_nut, M6_tap_radius, M6_clearance_radius]; +No632_pan_screw = ["No632_pan", "6-32 pan", hs_pan, 3.5, 6.9, 2.5, 0, 0, 0, M4_washer, false, No6_pilot_radius, No6_clearance_radius]; + +M3_hex_screw = ["M3_hex", "M3 hex", hs_hex, 3, 6.4, 2.125, 0, 0, 0, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; +M4_hex_screw = ["M4_hex", "M4 hex", hs_hex, 4, 8.1, 2.925, 0, 0, 0, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius]; +M5_hex_screw = ["M5_hex", "M5 hex", hs_hex, 5, 9.2, 3.65, 0, 0, 0, M5_washer, M5_nut, M5_tap_radius, M5_clearance_radius]; +M6_hex_screw = ["M6_hex", "M6 hex", hs_hex, 6,11.5, 4.15, 0, 0, 0, M6_washer, M6_nut, M6_tap_radius, M6_clearance_radius]; +M8_hex_screw = ["M8_hex", "M8 hex", hs_hex, 8, 15, 5.65, 0, 0, 22, M8_washer, M8_nut, M8_tap_radius, M8_clearance_radius]; + +M3_low_cap_screw = ["M3_low_cap", "M3 low cap", hs_cap, 3, 5.5, 2, 1.5, 2.0, 18, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; + +M3_grub_screw = ["M3_grub", "M3 grub", hs_grub, 3, 0, 0, 2.5, 1.5, 0, M3_washer, M3_nut, M3_tap_radius, M3_clearance_radius]; +M4_grub_screw = ["M4_grub", "M4 grub", hs_grub, 4, 0, 0, 2.4, 2.5, 0, M4_washer, M4_nut, M4_tap_radius, M4_clearance_radius]; + +No2_screw = ["No2", "No2 pan wood", hs_pan, 2.2, 4.2, 1.7, 0, 0, 0, M2p5_washer, false, No2_pilot_radius, No2_clearance_radius]; +No4_screw = ["No4", "No4 pan wood", hs_pan, 3.0, 5.5, 2.0, 0, 0, 0 ,M3p5_washer, false, No4_pilot_radius, No4_clearance_radius]; +No6_screw = ["No6", "No6 pan wood", hs_pan, 3.5, 6.7, 2.2, 0, 0, 0 , M4_washer, false, No6_pilot_radius, No6_clearance_radius]; +No6_cs_screw = ["No6_cs", "No6 cs wood", hs_cs, 3.5, 7.0, 0, 0, 0, 0, M4_washer, false, No6_pilot_radius, No6_clearance_radius]; + +screw_lists = [ +[ M2_cap_screw, M2p5_cap_screw, M3_cap_screw, M4_cap_screw, M5_cap_screw, M6_cap_screw, M8_cap_screw], +[ 0, 0, M3_low_cap_screw], +[ 0, 0, M3_hex_screw, M4_hex_screw, M5_hex_screw, M6_hex_screw, M8_hex_screw], +[ 0, M2p5_pan_screw, M3_pan_screw, M4_pan_screw, No632_pan_screw, M5_pan_screw, M6_pan_screw], +[ 0, No2_screw, No4_screw, No6_screw, No6_cs_screw], +[ 0, M2_cs_cap_screw,M3_cs_cap_screw, M4_cs_cap_screw], +[ 0, 0, M3_dome_screw, M4_dome_screw], +[ 0, 0, M3_grub_screw, M4_grub_screw] +]; + +use + +screws = [for(list = screw_lists) for(screw = list) screw]; + +function find_screw(type, size, i = 0) = + i >= len(screws) ? undef + : screw_head_type(screws[i]) == type && screw_radius(screws[i]) == size / 2 ? screws[i] + : find_screw(type, size, i + 1); + +function alternate_screw(type, screw) = + let(alt_screw = find_screw(type, screw_radius(screw) * 2)) + alt_screw ? alt_screw :screw; diff --git a/vitamins/sealing_strip.scad b/vitamins/sealing_strip.scad new file mode 100644 index 0000000..f8fb077 --- /dev/null +++ b/vitamins/sealing_strip.scad @@ -0,0 +1,53 @@ +// +// 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 . +// + +// +//! Sealing strip from B&Q used to seal around the door of 3D printers. +// +include <../core.scad> + +use <../utils/rounded_polygon.scad> + +r = 0.5; +h = 4; +h2 = 2; +h3 = 3; +w = 10; +w2 = 7; +w3 = 3; + +profile = [ + [ -w / 2 + r, r, r], + [ -w / 2 + r / 2, 2 * r + 0.1, -0.1], + [-w2 / 2, h - r, r], + [-w3 / 2, h2 + r,-r], + [ 0, h3 - r, r], + [ w3 / 2, h2 + r,-r], + [ w2 / 2, h - r, r], + [ w / 2 - r / 2, 2 * r + 0.1, -0.1], + [ w / 2 - r, r, r], +]; + +module sealing_strip(length) { //! Draw specified length of sealing strip + vitamin(str("sealing_strip(", length, "): Sealing strip 10mm x 4mm x ", length, "mm")); + rotate([90, 0, 90]) + color("Sienna") + linear_extrude(height = length, center = true) + rounded_polygon(profile); +} diff --git a/vitamins/sheet.scad b/vitamins/sheet.scad new file mode 100644 index 0000000..ac7cddc --- /dev/null +++ b/vitamins/sheet.scad @@ -0,0 +1,88 @@ +// +// 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 . +// + +// +//! Sheet materials. Rectangular with optional rounded corners. Negative radii make a chamfer. +//! +//! The "Soft" parameter can be used to determinesif the sheet material needs machine screws or wood screws, e.g.: +//! +//! * If soft, wood screws will be used, with a pilot hole. +//! * If not soft, either tapped holes or a clearance hole and nuts will be used to retain screws. +//! +//! The "Color" parameter is a quad-array: [R, G, B, Alpha], or can be a named color, see [OpenSCAD_User_Manual](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#color). +//! +//! For speed sheets should be modelled in 2D by subtracting holes from 2D templates made by ```sheet_2D()``` and then extruded to 3D with ```render_2D_sheet()```. +//! Note that modules that drill holes will return a 2D object if ```h``` is set to 0 to facilitate this. +// +include <../core.scad> + +function sheet_thickness(type) = type[2]; //! Thickness +function sheet_colour(type) = type[3]; //! Colour +function sheet_is_soft(type) = type[4]; //! Is soft enough for wood screws + +module corner(r) { + if(r > 0) + translate([r, -r]) + circle4n(r); + else + if(r < 0) + translate([-r, r]) + rotate(45) + square(-r * sqrt(2), -r * sqrt(2), center = true); + else + translate([0.5, -0.5]) + square(1, center = true); +} + +module sheet_2D(type, w, d, corners = [0, 0, 0, 0]) { //! 2D sheet template with specified size and optionally rounded corners + t = sheet_thickness(type); + vitamin(str("sheet(", type[0], ", ", w, ", ", d, arg(corners, [0, 0, 0, 0]), "): ", type[1], " ", round(w), "mm x ", round(d), "mm x ", t, "mm")); + + c = is_list(corners) ? corners : corners * [1, 1, 1, 1]; + + hull() { + translate([-w/2, d/2]) + corner(c[0]); + + translate([ w/2, d/2]) + rotate(-90) + corner(c[1]); + + translate([ w/2, -d/2]) + rotate(-180) + corner(c[2]); + + translate([-w/2, -d/2]) + rotate(-270) + corner(c[3]); + } +} + +module sheet(type, w, d, corners = [0, 0, 0, 0]) //! Draw speified sheet + linear_extrude(height = sheet_thickness(type), center = true) + sheet_2D(type, w, d, corners); + +module render_sheet(type, color = false) //! Render a sheet in the correct colour after holes have been subtracted + color(color ? color : sheet_colour(type)) + render() children(); + +module render_2D_sheet(type, color = false) //! Extrude a 2D sheet template and give it the correct colour + color(color ? color : sheet_colour(type)) + linear_extrude(height = sheet_thickness(type), center = true) + children(); diff --git a/vitamins/sheets.scad b/vitamins/sheets.scad new file mode 100644 index 0000000..8600ad1 --- /dev/null +++ b/vitamins/sheets.scad @@ -0,0 +1,50 @@ +// +// 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 . +// + +// +// Flat sheets +// + +// +// [ Code, Description, Thickness, Color, Soft] +// +mdf_colour = "#BEA587"; // sampled from a photo + +MDF6 = [ "MDF6", "Sheet MDF", 6, mdf_colour, true]; // ~1/4" +MDF10 = [ "MDF10", "Sheet MDF", 10, mdf_colour, true]; // ~3/8" +MDF12 = [ "MDF12", "Sheet MDF", 12, mdf_colour, true]; // ~1/2" +MDF18 = [ "MDF18", "Sheet MDF", 18, mdf_colour, true]; +MDF19 = [ "MDF19", "Sheet MDF", 19, mdf_colour, true]; // ~3/4" +PMMA3 = [ "PMMA3", "Sheet acrylic", 3, [1, 1, 1, 0.5 ], false]; // ~1/8" +PMMA6 = [ "PMMA6", "Sheet acrylic", 6, [1, 1, 1, 0.5 ], false]; // ~1/4" +PMMA8 = [ "PMMA8", "Sheet acrylic", 8, [1, 1, 1, 0.5 ], false]; // ~5/16" +PMMA10 = [ "PMMA10", "Sheet acrylic", 10, [1, 1, 1, 0.5 ], false]; // ~3/8" +glass2 = [ "glass2", "Sheet glass", 2, [1, 1, 1, 0.25 ], false]; +DiBond = [ "DiBond", "Sheet DiBond", 3, [0.2, 0.2, 0.2, 1 ], false]; +DiBond6 = [ "DiBond6", "Sheet DiBond", 6, "RoyalBlue", false]; +Cardboard = [ "Cardboard", "Corrugated cardboard", 5, [0.8, 0.6, 0.3, 1 ], false]; +FoilTape = [ "FoilTape", "Aluminium foil tape", 0.05,[0.9, 0.9, 0.9, 1 ], false]; +Foam20 = [ "Foam20", "Foam sponge", 20,[0.3, 0.3, 0.3, 1 ], true]; +AL6 = [ "AL6", "Aluminium tooling plate", 6, [0.9, 0.9, 0.9, 1 ], false]; +AL8 = [ "AL8", "Aluminium tooling plate", 8, [0.9, 0.9, 0.9, 1 ], false]; +Steel06 = [ "Steel06", "Sheet mild steel", 0.6,"silver" , false]; + +sheets = [MDF6, MDF10, MDF12, MDF19, PMMA3, PMMA6, PMMA8, PMMA10, glass2, DiBond, DiBond6, Cardboard, FoilTape, Foam20, AL6, AL8, Steel06]; + +use diff --git a/vitamins/spade.scad b/vitamins/spade.scad new file mode 100644 index 0000000..9585195 --- /dev/null +++ b/vitamins/spade.scad @@ -0,0 +1,59 @@ +// +// 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 . +// + +// +//! Spade terminals used as parts of electrical components. +// +include <../core.scad> + +function spade_l(type) = type[0]; //! Length of the narrow part +function spade_w(type) = type[1]; //! Width +function spade_t(type) = type[2]; //! Thickness +function spade_hole(type) = type[3]; //! Hole diameter +function spade_shank(type) = type[4]; //! Shank width + +module spade(type, height = 14) { //! Draw a spade of the specified type and total length. The shank length is adjusted to make the length. + w = spade_w(type); + l = spade_l(type); + chamfer = w / 4; + shank_w = spade_shank(type); + shank_l = height - spade_l(type); + + color("silver") + rotate([90, 0, 0]) + linear_extrude(height = spade_t(type), center = true) + difference() { + union() { + if(shank_l > 0) + translate([-shank_w / 2, 0]) + square([shank_w, shank_l]); + + translate([0, shank_l]) + hull() { + translate([- w/ 2, 0]) + square([w, l - chamfer]); + + translate([- (w - chamfer) / 2, 0]) + square([w - chamfer, l]); + } + } + translate([0, shank_l + l / 2]) + circle(d = spade_hole(type)); + } +} diff --git a/vitamins/spades.scad b/vitamins/spades.scad new file mode 100644 index 0000000..5789a9f --- /dev/null +++ b/vitamins/spades.scad @@ -0,0 +1,28 @@ +// +// 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 . +// + +spade3 = [3.8, 3.0, 0.4, 1.0, 3.9]; +spade6p4 = [8.3, 6.4, 0.8, 1.8, 8]; +spade4p8 = [6.4, 4.8, 0.5, 1.8, 8]; +spade4p8l = [7.0, 4.8, 0.5, 1.8, 8]; +spade4p8ll = [8.0, 4.8, 0.5, 1.8, 4.8]; + +spades = [spade3, spade6p4, spade4p8, spade4p8l, spade4p8ll]; + +use diff --git a/vitamins/spool.scad b/vitamins/spool.scad new file mode 100644 index 0000000..d820900 --- /dev/null +++ b/vitamins/spool.scad @@ -0,0 +1,59 @@ +// +// 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 . +// + +//! Filament spool models + +include <../core.scad> + +function spool_diameter(type) = type[1]; //! Outside diameter +function spool_width(type) = type[2]; //! Internal width +function spool_depth(type) = type[3]; //! Internal depth +function spool_rim_thickness(type) = type[4]; //! Thickness at the outside rim +function spool_hub_thickness(type) = type[5]; //! Thickness at the hub +function spool_hub_bore(type) = type[6]; //! Bore through the hub +function spool_hub_diameter(type) = type[7]; //! Diameter of the thicker hub +function spool_hub_taper(type) = type[8]; //! Diameter at which it tapers down to rim thickness +function spool_height(type) = spool_width(type) + 2 * spool_hub_thickness(type); //! Outside width + +module spool(type) { //! Draw specified spool + vitamin(str("spool(", type[0], "): Filament spool ", spool_diameter(type), " x ", spool_width(type))); + + h = spool_height(type); + r1 = spool_hub_bore(type) / 2; + r2 = spool_hub_diameter(type) / 2; + r3 = spool_hub_taper(type) / 2; + r4 = spool_diameter(type) / 2; + r5 = r4 - spool_depth(type); + + color([0.2, 0.2, 0.2]) translate_z(-h / 2) rotate_extrude(convexity = 5) + polygon([ + [r1, h], + [r1, 0], + [r2, 0], + [r3, spool_hub_thickness(type) - spool_rim_thickness(type)], + [r4, spool_hub_thickness(type) - spool_rim_thickness(type)], + [r4, spool_hub_thickness(type)], + [r5, spool_hub_thickness(type)], + [r5, h - spool_hub_thickness(type)], + [r4, h - spool_hub_thickness(type)], + [r4, h - spool_hub_thickness(type) + spool_rim_thickness(type)], + [r3, h - spool_hub_thickness(type) + spool_rim_thickness(type)], + [r2, h], + ]); +} diff --git a/vitamins/spools.scad b/vitamins/spools.scad new file mode 100644 index 0000000..59551d9 --- /dev/null +++ b/vitamins/spools.scad @@ -0,0 +1,32 @@ +// +// 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 . +// + +// Filament spool models + +// d w d r h b h h +// i i e i u o u u +// a d p m b r b b +// t t e +// h h t t d t +spool_300x85 = ["spool_300x85", 300, 85, 60, 4, 8, 52, 250, 280]; +spool_200x55 = ["spool_200x55", 200, 55, 40, 5, 5, 52, 200, 200]; + +spools = [spool_200x55, spool_300x85]; + +use diff --git a/vitamins/spring.scad b/vitamins/spring.scad new file mode 100644 index 0000000..a3a99b4 --- /dev/null +++ b/vitamins/spring.scad @@ -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 . +// + +// +//! Compression springs. Can be tapered, have open, closed or ground ends. Ground ends will render a lot slower. +// +include <../core.scad> + +use <../utils/sweep.scad> + +function spring_od(type) = type[1]; //! Outside diameter +function spring_gauge(type) = type[2]; //! Wire gauge +function spring_length(type) = type[3]; //! Uncompressed length +function spring_turns(type) = type[4]; //! Number of turns +function spring_closed(type) = type[5]; //! Are the ends closed +function spring_ground(type) = type[6]; //! Are the ends ground flat +function spring_od2(type) = type[7] ? type[7] : spring_od(type); //! Second diameter for spiral springs +function spring_colour(type) = type[8]; //! The colour +function spring_mesh(type) = type[9]; //! Optional pre-computed mesh + +function comp_spring(type, l = 0) = //! Calculate the mesh for spring + let(wire_d = spring_gauge(type), + r1 = (spring_od(type) - wire_d) / 2, + r2 = (spring_od2(type) - wire_d) / 2, + h = l ? l : spring_length(type), + H = spring_ground(type) ? h + wire_d * 0.75 : h - wire_d, + turns = spring_turns(type), + closed = spring_closed(type), + open = turns - 2 * closed, + open_H = H - 2 * closed * wire_d, + offset = (h - H) / 2, + sides = r2sides(r1), + path = [for(i = [0 : sides * turns], + t = i / sides, + top = t > turns / 2, + u = top ? turns - t : t, + v = (u < closed ? u < 0.25 ? 0 + : u < 1 ? wire_d * (u - 0.25) / 0.75 + : wire_d * u + : wire_d * closed + open_H / open * (u - closed) + ) + offset, + z = top ? h - v : v, + r = t <= closed ? r2 + : t >= turns - closed ? r1 + : r2 + (r1 - r2) * (t - closed) / open, + a = t * 360 + ) [r * sin(a), -r * cos(a), z]], + profile = circle_points(wire_d / 2 - eps, $fn = 16) + ) concat(type, [concat(sweep(path, profile), [l])]); + +module comp_spring(type, l = 0) { //! Draw specified spring, l can be set to specify the compressed length. + length = spring_length(type); + closed = spring_closed(type); + od = spring_od(type); + od2 = spring_od2(type); + gauge = spring_gauge(type); + ground = spring_ground(type); + vitamin(str("comp_spring(", type[0], arg(l, 0), + "): Spring ", od, od != od2 ? str(" - ", od2, "mm spiral") : "mm", " OD, ", gauge, "mm gauge x ", + length, "mm long, ", + closed ? "closed" : "open", + ground ? " ground" : "", " end" )); + + mesh = len(type) > 9 ? spring_mesh(type) : spring_mesh(comp_spring(type, l)); + assert(l == mesh[2], "can't change the length of a pre-generated spring"); + color(spring_colour(type)) + if(ground) + clip(zmin = 0, zmax = h) + polyhedron(mesh[0], mesh[1]); + else + polyhedron(mesh[0], mesh[1]); + + if($children) + translate_z(l) + children(); +} diff --git a/vitamins/springs.scad b/vitamins/springs.scad new file mode 100644 index 0000000..2972c24 --- /dev/null +++ b/vitamins/springs.scad @@ -0,0 +1,25 @@ +// +// 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 . +// + +peg_spring = ["peg_spring", 6.4, 0.9, 15.5, 8, 1, false, 0, "silver"]; +batt_spring = ["batt_spring", 5, 0.5, 8, 5, 1, false, 6, "silver"]; + +springs = [peg_spring, batt_spring]; + +use diff --git a/vitamins/ssr.scad b/vitamins/ssr.scad new file mode 100644 index 0000000..4d8d190 --- /dev/null +++ b/vitamins/ssr.scad @@ -0,0 +1,88 @@ +// +// 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 . +// + +// +//! Solid state relays. +// +include <../core.scad> + +function ssr_part(type) = type[1]; //! Description +function ssr_length(type) = type[2]; //! Length +function ssr_width(type) = type[3]; //! Width +function ssr_height(type) = type[4]; //! Height +function ssr_base_t(type) = type[5]; //! Thickness of metal base +function ssr_hole_d(type) = type[6]; //! Screw hole diameter +function ssr_hole_pitch(type) = type[7]; //! Difference between screw centres +function ssr_slot_w(type) = type[8]; //! Width of the screw slot in the body + +module ssr_hole_positions(type) //! Place children at the screw positions + for(end = [-1, 1]) + translate([end * ssr_hole_pitch(type) / 2, 0]) + children(); + +module ssr(type) { //! Draw specified SSR + vitamin(str("ssr(", type[0], "): Solid state relay ", ssr_part(type))); + + l = ssr_length(type); + w = ssr_width(type); + t = ssr_base_t(type); + h = ssr_height(type); + + color("silver") linear_extrude(height = t) difference() { + square([l, w], center = true); + + ssr_hole_positions(type) + circle(d = ssr_hole_d(type)); + } + color([242/255, 236/255, 220/255]) + translate_z(t) + linear_extrude(height = h - t) difference() { + square([l, w], center = true); + + for(end = [-1, 1]) + hull() { + translate([end * ssr_hole_pitch(type) / 2, 0]) + circle(d = ssr_slot_w(type)); + + translate([end * ssr_hole_pitch(type), 0]) + circle(d = ssr_slot_w(type)); + } + } +} + +use +use +use + +module ssr_assembly(type, screw, thickness) { //! Assembly with fasteners in place + nut = screw_nut(screw); + washer = screw_washer(screw); + screw_length = screw_longer_than(2 * washer_thickness(washer) + thickness + ssr_base_t(type) + nut_thickness(nut, true)); + + ssr(type); + + ssr_hole_positions(type) { + translate_z(ssr_base_t(type)) + nut_and_washer(nut, true); + + translate_z(-thickness) + vflip() + screw_and_washer(screw, screw_length); + } +} diff --git a/vitamins/ssrs.scad b/vitamins/ssrs.scad new file mode 100644 index 0000000..858486d --- /dev/null +++ b/vitamins/ssrs.scad @@ -0,0 +1,33 @@ +// +// 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 . +// + +// +// p l w h b h p s +// a e i e a o i l +// r n d i s l t o +// t g t g e e c t +// t h h h +// h t d w +// +SSR10DA = [ "SSR10DA", "Robodigg 10A", 58, 45, 33, 2.5, 5, 47, 9 ]; +SSR25DA = [ "SSR25DA", "Fotek 25A", 63, 45, 23, 4.6, 5, 47, 10 ]; + +ssrs = [SSR25DA, SSR10DA]; + +use diff --git a/vitamins/stepper_motor.scad b/vitamins/stepper_motor.scad new file mode 100644 index 0000000..616e547 --- /dev/null +++ b/vitamins/stepper_motor.scad @@ -0,0 +1,123 @@ +// +// 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 . +// + +// +//! NEMA stepper motor model. +// +include <../core.scad> + +include +use +include +use <../utils/tube.scad> + +function NEMA_width(type) = type[1]; //! Width of the square face +function NEMA_length(type) = type[2]; //! Body length +function NEMA_radius(type) = type[3]; //! End cap radius +function NEMA_body_radius(type) = type[4]; //! Body radius +function NEMA_boss_radius(type) = type[5]; //! Boss around the spindle radius +function NEMA_boss_height(type) = type[6]; //! Boss height +function NEMA_shaft_dia(type) = type[7]; //! Shaft diameter +function NEMA_shaft_length(type)= type[8]; //! Shaft length above the face +function NEMA_hole_pitch(type) = type[9]; //! Screw hole pitch +function NEMA_holes(type) = [-NEMA_hole_pitch(type) / 2, NEMA_hole_pitch(type) / 2]; //! Screw positions for for loop +function NEMA_big_hole(type) = NEMA_boss_radius(type) + 0.2; //! Clearance hole for the big boss + +stepper_body_colour = "black"; +stepper_cap_colour = grey50; + +module NEMA_outline(type) //! 2D outline + intersection() { + side = NEMA_width(type); + square([side, side], center = true); + + circle(NEMA_radius(type)); + } + +module NEMA(type) { //! Draw specified NEMA stepper motor + side = NEMA_width(type); + length = NEMA_length(type); + body_rad = NEMA_body_radius(type); + boss_rad = NEMA_boss_radius(type); + boss_height =NEMA_boss_height(type); + shaft_rad = NEMA_shaft_dia(type) / 2; + cap = 8; + vitamin(str("NEMA(", type[0], "): Stepper motor NEMA", round(NEMA_width(type) / 2.54), " x ", length, "mm")); + + union() { + color(stepper_body_colour) // black laminations + translate_z(-length / 2) + linear_extrude(height = length - cap * 2, center = true) + intersection() { + square([side, side], center = true); + + circle(body_rad); + } + + color(stepper_cap_colour) { // aluminium end caps + tube(or = boss_rad, ir = shaft_rad + 2, h = boss_height * 2); // raised boss + + for(end = [-1, 1]) + translate_z(-length / 2 + end * (length - cap) / 2) + linear_extrude(height = cap, center = true) + difference() { + intersection() { + square([side, side], center = true); + circle(NEMA_radius(type)); + } + if(end > 0) + for(x = NEMA_holes(type), y = NEMA_holes(type)) + translate([x, y]) + circle(r = 3/2); + } + } + + color(NEMA_shaft_length(type) > 50 ? "silver" : stepper_cap_colour) + translate_z(-5) + cylinder(r = shaft_rad, h = NEMA_shaft_length(type) + 5); // shaft + + translate([0, side / 2, -length + cap / 2]) + rotate([90, 0, 0]) + for(i = [0 : 3]) + rotate(225 + i * 90) + color(["red", "blue","green","black"][i]) + translate([1, 0, 0]) + cylinder(r = 1.5 / 2, h = 12, center = true); + } +} + +module NEMA_screw_positions(type, n = 4) { //! Positions children at the screw holes + pitch = NEMA_hole_pitch(type); + + for($i = [0 : n - 1]) + rotate($i * 90) + translate([pitch / 2, pitch / 2]) + rotate($i * -90) + children(); +} + +module NEMA_screws(type, screw, n = 4, screw_length = 8, earth = undef) //! Place screws and optional earth tag + NEMA_screw_positions(type, n) + if($i != earth) + screw_and_washer(screw, screw_length, true); + else + rotate($i > 1 ? 180 : 0) + ring_terminal(M3_ringterm) + star_washer(screw_washer(screw)) + screw(screw, screw_length); diff --git a/vitamins/stepper_motors.scad b/vitamins/stepper_motors.scad new file mode 100644 index 0000000..1a233b1 --- /dev/null +++ b/vitamins/stepper_motors.scad @@ -0,0 +1,36 @@ +// +// 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 . +// + +// +// NEMA stepper motor model +// + +// corner body boss boss shaft +// side, length, radius, radius, radius, depth, shaft, length, holes +NEMA17 = ["NEMA17", 42.3, 47, 53.6/2, 25, 11, 2, 5, 24, 31 ]; +NEMA17M = ["NEMA17M", 42.3, 40, 53.6/2, 25, 11, 2, 5, 20, 31 ]; +NEMA17M8= ["NEMA17M8", 42.3, 40, 53.6/2, 25, 11, 2, 8, 280, 31 ]; +NEMA17S = ["NEMA17S", 42.3, 34, 53.6/2, 25, 11, 2, 5, 24, 31 ]; +NEMA16 = ["NEMA16", 39.5, 19.2, 50.6/2, 50.6/2, 11, 2, 5, 12, 31 ]; +NEMA14 = ["NEMA14", 35.2, 36, 46.4/2, 21, 11, 2, 5, 21, 26 ]; +NEMA23 = ["NEMA23", 56.4, 51.2, 75.7/2, 35, 38.1/2, 1.6, 6.35, 24, 47.1 ]; + +stepper_motors = [NEMA14, NEMA16, NEMA17S, NEMA17M, NEMA17, NEMA23]; + +use diff --git a/vitamins/toggle.scad b/vitamins/toggle.scad new file mode 100644 index 0000000..f531f9c --- /dev/null +++ b/vitamins/toggle.scad @@ -0,0 +1,157 @@ +// +// 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 . +// + +// +//! Toggle switches +// +include <../core.scad> +use +use + +function toggle_part(type) = type[1]; //! Part description +function toggle_width(type) = type[2]; //! Body width +function toggle_height(type) = type[3]; //! Body height +function toggle_depth(type) = type[4]; //! Body depth +function toggle_thickness(type)= type[5]; //! Metal thickness +function toggle_inset(type) = type[6]; //! How far the metal is inset into the body +function toggle_colour(type) = type[7]; //! Body colour +function toggle_od(type) = type[8]; //! Barrel outside diameter +function toggle_id(type) = type[9]; //! Barrel inside diameter +function toggle_thread(type) = type[10]; //! Length of threaded barrel +function toggle_collar_d(type) = type[11]; //! Collar diameter +function toggle_collar_t(type) = type[12]; //! Collar thickness +function toggle_pivot(type) = type[13]; //! Z offset of the pivot point above the top of the body +function toggle_angle(type) = type[14]; //! Angle of the paddle +function toggle_paddle_l(type) = type[15]; //! Length of the paddle +function toggle_paddle_d1(type)= type[16]; //! Diameter at the top of the paddle +function toggle_paddle_w(type) = type[17]; //! Width at the top for non-spherical end +function toggle_nut(type) = type[18]; //! Nut type +function toggle_washer(type) = type[19]; //! Washer type +function toggle_pins(type) = type[20]; //! Number of pins +function toggle_pin_l(type) = type[21][0]; //! Pin length +function toggle_pin_w(type) = type[21][1]; //! Pin width +function toggle_pin_t(type) = type[21][2]; //! Pin thickness +function toggle_pin_vp(type) = type[21][3]; //! Pin y pitch +function toggle_pin_hp(type) = type[21][4]; //! Pin x pitch + +function toggle_hole_radius(type) = toggle_od(type) / 2 + 0.1; //! Radius of the panel hole + +module toggle(type, thickness) { //! Draw specified toggle switch with the nuts and washers positioned for the specified panel thickness + vitamin(str("toggle(", type[0], ", 3): Toggle switch ", toggle_part(type))); + + inset = toggle_inset(type); + t = toggle_thickness(type); + h1 = toggle_depth(type) - t; + h2 = toggle_depth(type) - inset; + t2 = (toggle_od(type) - toggle_id(type)) / 2; + nut = toggle_nut(type); + washer = toggle_washer(type); + chamfer = t2 / 2; + thread = toggle_thread(type); + stack = chamfer + nut_thickness(nut) + 3 * washer_thickness(washer) + thickness + toggle_collar_t(type); + back_nut = thread - stack > nut_thickness(nut); + gap = back_nut ? thread - stack - nut_thickness(nut) : 0; + + module stack() + washer(washer) + translate_z(thickness) + explode(20, true) washer(washer) + explode(5, true) star_washer(washer) + explode(5) nut(nut); + + translate_z(-washer_thickness(washer) - (back_nut ? nut_thickness(nut) : 0) - gap - toggle_collar_t(type)) { + color(toggle_colour(type)) + translate_z(-h1 / 2 - t) + cube([toggle_width(type), toggle_height(type), h1], center = true); + + color("silver") { + if(toggle_collar_t(type)) + cylinder(d = toggle_collar_d(type), h = toggle_collar_t(type)); + + translate_z(-t / 2) + cube([toggle_width(type), toggle_height(type), t], center = true); + + translate_z(-h2 / 2) + cube([toggle_width(type) + 2 * eps, toggle_height(type) - 2 * inset, h2], center = true); + + rotate_extrude() + difference() { + hull() { + square([toggle_od(type) / 2, thread - chamfer]); + + square([toggle_od(type) / 2 - chamfer, thread]); + } + square([toggle_id(type) / 2, thread + 1]); + } + + translate_z(toggle_pivot(type)) { + angle = toggle_angle(type); + l1 = toggle_paddle_l(type); + l2 = toggle_thread(type) - toggle_pivot(type); + l = l1 + l2; + sphere(d = toggle_id(type)); + + d1 = toggle_paddle_d1(type); + d2 = toggle_id(type) - 2 * l2 * tan(abs(angle)); + d3 = d2 - (d1 - d2) * l2 / l1; + + hull() { + rotate([max(angle, 0), 0, 0]) + if(toggle_paddle_w(type)) + translate_z(l) + linear_extrude(height = eps, center = true) + intersection() { + circle(d = d1); + + square([d1 + 1, toggle_paddle_w(type)], center = true); + } + else + translate_z(l - d1 / 2) sphere(d = d1); + + rotate([max(angle, 0), 0, 0]) + translate_z(l2) + cylinder(d = d2, h = eps); + + sphere(d = d3); + } + } + } + pins = toggle_pins(type); + rows = pins > 3 ? 2 : 1; + color("gold") + translate_z(-toggle_depth(type) - toggle_pin_l(type) / 2) + linear_extrude(height = toggle_pin_l(type), center = true) + for(i = [0 : pins - 1]) { + x = rows < 2 ? 0 : (i % 2) - 0.5; + y = rows < 2 ? i - 1 : floor(i / 2) - 1; + translate([x * toggle_pin_hp(type), y * toggle_pin_vp(type)]) + square([toggle_pin_w(type), toggle_pin_t(type)], center = true); + } + + not_on_bom() + translate_z(gap + toggle_collar_t(type)) + if(back_nut) + nut(nut) stack(); + else + stack(); + } +} + +module toggle_hole(type, h = 100) //! Drill the hole in a panel + drill(toggle_hole_radius(type), h); diff --git a/vitamins/toggles.scad b/vitamins/toggles.scad new file mode 100644 index 0000000..2112990 --- /dev/null +++ b/vitamins/toggles.scad @@ -0,0 +1,43 @@ +// +// 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 . +// + +// +// +// p +// a +// r +// t +// +// +// l w t vp hp +CK7000_tag = [3.94, 2.03, 0.76, 4.7, 4.83]; +CK7000_pin = [6.1, 1.5, 0.76, 4.7, 4.83]; +AP5236_pin = [5.2 , 1.0, 0.8, 4.7, 4.83]; +MS332F_pin = [4.0 , 1.0, 1.0, 4.7, 4.83]; + +// w l d t i c od id thread pv a tl pd pw +CK7101 = ["CK7101", "CK7101", 6.86, 12.7, 8.89, 0.4, 1.7, "red", 6.1, 4, 8.89, 0, 0, 4.45, 25/2, 10.67, 2.92, 0, toggle_nut, toggle_washer, 3, CK7000_tag]; +CK7105 = ["CK7105", "CK7101", 6.86, 12.7, 8.89, 0.4, 1.7, "red", 6.1, 4, 8.89, 0, 0, 4.45,-25/2, 21.33, 5.08, 2.54,toggle_nut, toggle_washer, 3, CK7000_pin]; + +AP5236 = ["AP5236", "AP5236", 7.0, 13.6, 11, 0.4, 1.7, "blue",6.1, 4, 8.0 , 8, 1, 3.0 , 25/2, 22.2, 4.90, 2.50,toggle_nut, toggle_washer, 3, AP5236_pin]; +MS332F = ["MS332F", "MS332F", 12.6, 13.1, 9.5, 0.4, 1.7, "blue",6.1, 4, 8.0 , 8, 1, 4.0 , 25/2, 14.4, 5.0, 2.2 ,toggle_nut, toggle_washer, 6, MS332F_pin]; + +toggles = [CK7101, CK7105, AP5236, MS332F]; + +use diff --git a/vitamins/transformer.scad b/vitamins/transformer.scad new file mode 100644 index 0000000..b448577 --- /dev/null +++ b/vitamins/transformer.scad @@ -0,0 +1,76 @@ +// +// 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 . +// + +// +//!Iron core transformers. The grey shaded area is the keep out region where the terminals are. +// +include <../core.scad> +use + +function tx_part(type) = type[1]; //! Part description +function tx_width(type) = type[2]; //! Bounding width of the core +function tx_depth(type) = type[3]; //! Bounding depth of the bobbin +function tx_height(type) = type[4]; //! Bounding height of the transformer +function tx_x_pitch(type) = type[5]; //! Screw hole x pitch +function tx_y_pitch(type) = type[6]; //! Screw hole y pitch when four screws +function tx_screw(type) = type[7]; //! Screw type +function tx_foot_thickness(type) = type[8]; //! Thickness of the foot +function tx_foot_width(type) = type[9]; //! Width of the foot +function tx_foot_depth(type) = type[10]; //! Depth of the foot +function tx_lamination_depth(type) = type[11]; //! Lamination depth +function tx_lamination_height(type) = type[12]; //! Lamination height +function tx_bobbin_offset(type) = type[13]; //! Vertical offset of the bobbin from the centre of the laminations +function tx_bobbin_width(type) = type[14]; //! Bobbin width +function tx_bobbin_height(type) = type[15]; //! Bobbin height +function tx_bobbin_radius(type) = type[16]; //! Bobbin corner radius + +module transformer(type) { //! Draw specified transformer + vitamin(str("transformer(", type[0], "): Transformer ", tx_part(type))); + + color("silver") { + linear_extrude(height = tx_foot_thickness(type)) + difference() { + rounded_square([tx_foot_width(type), tx_foot_depth(type)], r = 2); + + transformer_hole_positions(type) + circle(screw_clearance_radius(tx_screw(type))); + } + translate_z(tx_lamination_height(type) / 2) + cube([tx_width(type), tx_lamination_depth(type), tx_lamination_height(type)], center = true); + + } + + color("white") { + translate_z(tx_lamination_height(type) / 2 + tx_bobbin_offset(type) / 2) + rounded_rectangle([tx_bobbin_width(type), tx_depth(type), tx_bobbin_height(type)], r = tx_bobbin_radius(type)); + } + terminal_height = tx_height(type) - tx_lamination_height(type); + + if(terminal_height) + %translate_z(tx_lamination_height(type) + terminal_height / 2) union() { + cube([tx_width(type), tx_lamination_depth(type), terminal_height], center = true); + + cube([tx_bobbin_width(type), tx_depth(type), terminal_height], center = true); + } +} + +module transformer_hole_positions(type) //! Position children at the mounting hole positions + for(x = [-1, 1], y = tx_y_pitch(type) ? [-1, 1] : 0) + translate([x * tx_x_pitch(type) / 2, y * tx_y_pitch(type) / 2]) + children(); diff --git a/vitamins/transformers.scad b/vitamins/transformers.scad new file mode 100644 index 0000000..5f83717 --- /dev/null +++ b/vitamins/transformers.scad @@ -0,0 +1,37 @@ +// +// 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 . +// + +// +// w d h x y s f f f l l b b b b +// i e e p p c o o o a a o o o o +// d p i i i r o o o m m b b b b +// t t g t t e t t t +// h h h c c w d h o w h r +// t h h t w d e e f i e a +// h i e p i f d i d +// i d p t g s t g i +// c t t h h e h h u +// k h h t t t s +// +CCM300 = ["CCM300", "Carroll & Meynell CCM300/230 isolation", 120, 88, 120, 90, 68, M5_pan_screw, 2, 111, 86, 42, 106, 6, 79, 62, 8]; +SMALLTX= ["SMALLTX", "Small mains", 38, 32, 33, 47, 0, M3_pan_screw,.8, 58, 12, 16, 33, 0, 25, 20, 2]; + +transformers = [SMALLTX, CCM300]; + +use diff --git a/vitamins/tubing.scad b/vitamins/tubing.scad new file mode 100644 index 0000000..6065aec --- /dev/null +++ b/vitamins/tubing.scad @@ -0,0 +1,45 @@ +// +// 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 . +// + +// +//! Tubing and sleeving. The internal diameter can be forced to stretch it over something. +// +include <../core.scad> + +function tubing_material(type) = type[1]; //! Material description +function tubing_od(type) = type[2]; //! Outside diameter +function tubing_id(type) = type[3]; //! Inside diameter +function tubing_colour(type) = type[4]; //! Colour + +module tubing(type, length = 15, forced_id = 0) { //! Draw specified tubing with optional forced internal diameter + original_od = tubing_od(type); + original_id = tubing_id(type); + id = forced_id ? forced_id : original_id; + od = original_od + id - original_id; + if(tubing_material(type) == "Heatshrink sleeving") + vitamin(str("tubing(", type[0], arg(length, 15), "): ", tubing_material(type), " ID ", original_id, "mm x ",length, "mm")); + else + vitamin(str("tubing(", type[0], arg(length, 15), "): ", tubing_material(type), " OD ", original_od, "mm ID ", original_id,"mm x ",length, "mm")); + color(tubing_colour(type)) + linear_extrude(height = length, center = true, convexity = 3) + difference() { + circle(d = od); + circle(d = id); + } +} diff --git a/vitamins/tubings.scad b/vitamins/tubings.scad new file mode 100644 index 0000000..68e004a --- /dev/null +++ b/vitamins/tubings.scad @@ -0,0 +1,39 @@ +// +// 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 . +// + +// +// Tubing and sleeving +// +tubing_colour = [0.8, 0.8, 0.8, 0.75 ]; + +PVC64 = ["PVC64", "PVC aquarium tubing", 6, 4, tubing_colour]; +PVC85 = ["PVC85", "PVC aquarium tubing", 8, 5, tubing_colour]; +NEOP85 = ["NEOP85", "Neoprene tubing", 8, 5, [0.2,0.2,0.2]]; +PTFE07 = ["PTFE07", "PTFE sleeving", 1.2, 0.71, tubing_colour]; +PTFE20 = ["PTFE20", "PTFE sleeving", 2.6, 2, tubing_colour]; +PF7 = ["PF7", "PTFE tubing", 46/10, 3.84, tubing_colour]; +HSHRNK16 = ["HSHRNK16", "Heatshrink sleeving", 2.0, 1.6, "grey"]; +HSHRNK24 = ["HSHRNK24", "Heatshrink sleeving", 2.8, 2.4, "grey"]; +HSHRNK32 = ["HSHRNK32", "Heatshrink sleeving", 3.6, 3.2, "grey"]; +HSHRNK64 = ["HSHRNK64", "Heatshrink sleeving", 6.8, 6.4, "grey"]; +HSHRNK100 = ["HSHRNK100", "Heatshrink sleeving",10.4, 10.0, [0.2,0.2,0.2]]; + +tubings = [PVC64, PVC85, NEOP85, PTFE07, PTFE20, PF7, HSHRNK16, HSHRNK24, HSHRNK64, HSHRNK100]; + +use diff --git a/vitamins/variac.scad b/vitamins/variac.scad new file mode 100644 index 0000000..af8632e --- /dev/null +++ b/vitamins/variac.scad @@ -0,0 +1,108 @@ +// +// 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 . +// + +// +//! Variable auto transformers. +// +include <../core.scad> +use + +function variac_diameter(type) = type[2]; //! Body diameter +function variac_height(type) = type[3]; //! Body height +function variac_bulge_dia(type) = type[4]; //! Bulge to opposite edge +function variac_bulge_width(type) = type[5]; //! Width of the bulge +function variac_shaft_dia(type) = type[6]; //! Shaft diameter +function variac_shaft_length(type) = type[7]; //! Shaft length +function variac_screws(type) = type[8]; //! Number of screws +function variac_screw_pitch(type) = type[9]; //! Pitch of screws +function variac_screw(type) = type[10]; //! Screw type +function variac_dial_dia(type) = type[11]; //! Dial diameter +function variac_dial_thickness(type) = type[12]; //! Dial thickness +function variac_dial_hole_pitch(type)= type[13] ? type[13] : variac_screw_pitch(type); //! Screw pitch for the dial +function variac_dial_hole_r(type) = type[14] ? type[14] : screw_clearance_radius(variac_screw(type)); //! Dial screw hole radius +function variac_dial_big_hole(type) = type[15] ? type[15] : variac_shaft_dia(type) + 2; //! Central dial hole diameter + +function variac_radius(type) = variac_diameter(type) / 2; //! Body radius + +module variac_hole_positions(type, pitch = undef) //! Position children at the screw positions + for(i = [0 : variac_screws(type) - 1]) + rotate(360 * (i + 0.5) / variac_screws(type) - 90) + translate([pitch ? pitch : variac_screw_pitch(type), 0]) + children(); + +module variac_holes(type, h = 100) { //! Drill panel holes for specified variac + variac_hole_positions(type) + drill(screw_clearance_radius(variac_screw(type)), h); + + drill(variac_shaft_dia(type) / 2 + 1, h); +} + +module variac_dial(type) //! Draw the dial for the specified variac + color("silver") linear_extrude(height = variac_dial_thickness(type)) + difference() { + circle(d = variac_dial_dia(type)); + + circle(variac_dial_big_hole(type) / 2); + + variac_hole_positions(type, variac_dial_hole_pitch(type)) + circle(variac_dial_hole_r(type)); + } + +module variac(type, thickness = 3, dial = true) { //! Draw the specified variac with screws and possibly the dial when it is fixed and not rotating + vitamin(str("variac(", type[0], ", 3): Variac ", type[1])); + dia = variac_diameter(type); + w = variac_bulge_width(type); + h = variac_height(type); + + bulge_r = variac_bulge_dia(type) - dia / 2; + + module shape() { + circle(d = dia); + + translate([-w / 2, -bulge_r]) + square([w, bulge_r]); + } + + translate_z(-h) { + color("#A66955") { + linear_extrude(height = h) + difference() { + shape(); + + variac_hole_positions(type) + circle(screw_radius(variac_screw(type))); + } + + linear_extrude(height = h - 10) + shape(); + } + color("silver") + translate_z(1) + cylinder(d = variac_shaft_dia(type), h = h + variac_shaft_length(type) - 1); + + if(dial) + translate_z(thickness + h) + variac_dial(type); + + translate_z(thickness + h + (dial ? variac_dial_thickness(type) : 0)) + not_on_bom() + variac_hole_positions(type) + screw_and_washer(variac_screw(type), 16); + } +} diff --git a/vitamins/variacs.scad b/vitamins/variacs.scad new file mode 100644 index 0000000..f0e698e --- /dev/null +++ b/vitamins/variacs.scad @@ -0,0 +1,36 @@ +// +// 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 . +// + +// +// +// d h b b s s s p s d d +// i e u u h h c i c i i +// a i l l a a r t r a a +// m g g g f f e c e l l +// e h e e t t w h w +// t s d t +// e d w d l i h +// r a k +// +RAVISTAT1F1 = ["RAVISTAT1F1", "RAVISTAT 1F-1", 85, 75, 105, 32, 6, 22, 2, 14, M4_pan_screw, 65, 0.5]; +DURATRAKV5HM = ["DURATRAKV5HM", "DURATRAK V5HM", 125, 120, 148, 49, 9.6, 25, 3, 38.1,M5_pan_screw, 104, 1.66, 15.875, 2, 22]; + +variacs = [RAVISTAT1F1, DURATRAKV5HM]; + +use diff --git a/vitamins/veroboard.scad b/vitamins/veroboard.scad new file mode 100644 index 0000000..9b62ca9 --- /dev/null +++ b/vitamins/veroboard.scad @@ -0,0 +1,175 @@ +// +// 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 . +// + +// +//! Veroboard with mounting holes, track breaks, removed tracks, solder points and components. +// +include <../core.scad> +use +include <../vitamins/screws.scad> + +function vero_assembly(type) = type[1]; //! Name of the assembly +function vero_holes(type) = type[2]; //! Number of holes in each strip +function vero_strips(type) = type[3]; //! Number of strips +function vero_pitch(type) = type[4]; //! Hole pitch +function vero_fr4(type) = type[5]; //! True if FR4 rather than SRBP +function vero_screw(type) = type[6]; //! Mounting screw type +function vero_mounting_holes(type) = type[7]; //! Positions of the mounting holes +function vero_breaks(type) = type[8]; //! Breaks in the tracks +function vero_no_track(type) = type[9]; //! Missing tracks +function vero_components(type) = type[10]; //! List of named components and their positions +function vero_joints(type) = type[11]; //! List of solder joints + +function vero_thickness(type) = 1.6; //! Thickness of the substrate +function vero_track_thickness(type)= 0.035; //! Thickness of the tracks +function vero_track_width(type) = vero_pitch(type) * 0.8; //! The width of the tracks +function vero_length(type) = vero_holes(type) * vero_pitch(type); //! Length of the board +function vero_width(type) = vero_strips(type) * vero_pitch(type); //! Width of the board + +module solder_meniscus(type) { + h = 1; + r = vero_track_width(type) / 2; + + translate_z(vero_track_thickness(type)) + color("silver") rotate_extrude() + difference() { + square([r, h]); + + translate([r - eps, h + eps]) + ellipse(r , h); + } +} + +module vero_grid_pos(type, x, y) { //! Convert grid position to offset from the centre + holes = vero_holes(type); + strips = vero_strips(type); + translate([((x + holes) % holes) - holes / 2 + 0.5, + ((y + strips) % strips) - strips / 2 + 0.5] * vero_pitch(type)) + children(); +} + +module vero_mounting_hole_positions(type) //! Positions children at the mounting holes + for(p = vero_mounting_holes(type)) + vero_grid_pos(type, p.x, p.y) + children(); + +module vero_mounting_holes(type, h = 100) //! Drill mounting holes in a panel + vero_mounting_hole_positions(type) + drill(screw_clearance_radius(vero_screw(type)), h); + +module veroboard(type) { //! Draw specified veroboard with missing tracks and track breaks + holes = vero_holes(type); + strips = vero_strips(type); + pitch = vero_pitch(type); + length = holes * pitch; + width = strips * pitch; + hole_d = 1; + tw = vero_track_width(type); + colour = vero_fr4(type) ? "green" : "goldenrod"; + tc = vero_fr4(type) ? "silver" : "darkorange"; + no_track = vero_no_track(type); + + vitamin(str("veroboard(", type[0], "): Veroboard ", holes, " holes x ", strips, "strips")); + + color(colour) linear_extrude(height = vero_thickness(type)) + difference() { + rounded_square([length, width], r = 0.5, center = true); + + for(x = [0 : holes - 1], y = [0 : strips - 1]) + vero_grid_pos(type, x, y) + circle(d = hole_d); + + vero_mounting_hole_positions(type) + circle(r = screw_radius(vero_screw(type))); + } + + color(tc) vflip() linear_extrude(height = vero_track_thickness(type)) + difference() { + vflip() + for(y = [0 : strips -1]) + translate([0, y * pitch - (strips - 1) * pitch / 2]) + if(!in(no_track, y)) + difference() { + square([length - (pitch - tw), tw], center = true); + + for(x = [0 : holes - 1]) + translate([x * pitch - (holes - 1) * pitch / 2, 0]) + circle(d = hole_d); + } + vflip() { + vero_mounting_hole_positions(type) + for(y = [-1 : 1]) + hull() + for(x = [-1, 1]) + translate([x, y] * pitch) + circle(d = pitch * 1.1); + + for(p = vero_breaks(type)) + vero_grid_pos(type, p.x, p.y) + if(ceil(p.x) == p.x) + circle(d = pitch); + else + square([pitch * 0.2, pitch], center = true); + } + } +} + +module vero_components(type, cutouts = false, angle = undef) + for(comp = vero_components(type)) + vero_grid_pos(type, comp.x, comp.y) + translate_z(vero_thickness(type)) + pcb_component(comp, cutouts, angle); + +module vero_cutouts(type, angle = undef) vero_components(type, true, angle); //! Make cutouts to clear components + +module veroboard_assembly(type, height, thickness, flip = false) //! Draw the assembly with components and fasteners in place +assembly(vero_assembly(type)) { + screw = vero_screw(type); + washer = screw_washer(screw); + nut = screw_nut(screw); + screw_length = screw_longer_than(height + thickness + vero_thickness(type) + 2 * washer_thickness(washer) + nut_thickness(nut, true)); + + translate_z(height) { + veroboard(type); + + vero_components(type); + + for(r = vero_joints(type)) + for(x = r.x, y = r.y) + vero_grid_pos(type, x, y) + vflip() + solder_meniscus(type); + } + vero_mounting_hole_positions(type) { + translate_z(height + vero_thickness(type)) + if(flip) + nut_and_washer(nut, true); + else + screw_and_washer(screw, screw_length); + + color(pp1_colour) pcb_spacer(screw, height); + + translate_z(-thickness) + vflip() + if(flip) + screw_and_washer(screw, screw_length); + else + nut_and_washer(nut, true); + } +} diff --git a/vitamins/washer.scad b/vitamins/washer.scad new file mode 100644 index 0000000..fe2bf07 --- /dev/null +++ b/vitamins/washer.scad @@ -0,0 +1,130 @@ +// +// 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 . +// + +// +//! Washers, star washers, penny washers and printed washers. +//! +//! If a washer is given a child, usually a screw or a nut, then it is placed on its top surface. +// +include <../core.scad> +include <../utils/sweep.scad> + +soft_washer_colour = grey20; +hard_washer_colour = grey80; +star_washer_colour = brass; + +function washer_size(type) = type[1]; //! Noiminal size +function washer_diameter(type) = type[2]; //! External diameter +function washer_thickness(type) = type[3]; //! Thickness +function washer_soft(type) = type[4]; //! True if rubber +function star_washer_diameter(type) = type[5]; //! Star version size +function spring_washer_diameter(type) = type[6]; //! Spring washer size +function spring_washer_thickness(type)= type[7]; //! Spring washer thickness +function penny_washer(type) = type[8]; //! Corresponding penny washer +function washer_radius(type) = washer_diameter(type) / 2; //! Outside radius + +function washer_id(type) = washer_size(type) + 0.1; //! Inside diameter +function washer_colour(type) = washer_soft(type) ? soft_washer_colour : hard_washer_colour; //! Washer colour + +module washer(type) { //! Draw specified washer + hole = washer_size(type); + thickness = washer_thickness(type); + diameter = washer_diameter(type); + p = penny_washer(type); + penny = !is_undef(p) && !is_list(p); + if(washer_soft(type)) + vitamin(str("washer(", type[0], "_washer): Washer rubber M", hole, " x ", diameter, "mm x ", thickness, "mm")); + else + vitamin(str("washer(", type[0], "_washer): Washer ", penny ? "penny " : "", " M", hole, " x ", diameter, "mm x ", thickness, "mm")); + color(washer_colour(type)) + linear_extrude(height = thickness - 0.05) + difference() { + circle(d = diameter); + circle(d = washer_id(type)); + } + + if($children) + translate_z(thickness) + children(); +} + +module penny_washer(type) { //! Draw penny version of specified plain washer + penny = penny_washer(type); + assert(penny, "no penny version"); + washer(penny) + children(); +} + +module star_washer(type) { //! Draw star version of washer + hole = washer_size(type); + thickness = washer_thickness(type); + diameter = star_washer_diameter(type); + rad = diameter / 2; + inner = (hole / 2 + rad) / 2; + spoke = rad - hole / 2; + vitamin(str("star_washer(", type[0], "_washer): Washer star M", hole, " x ", thickness, "mm")); + color(star_washer_colour) + linear_extrude(height = thickness) + difference() { + circle(rad); + + circle(d = washer_id(type)); + + for(a = [0:30:360]) + rotate(a) + translate([inner + spoke / 2, 0, 0.5]) + square([spoke, 2 * PI * inner / 36], center = true); + } + if($children) + translate_z(thickness) + children(); +} + +module spring_washer(type) { //! Draw spring version of washer + hole = washer_size(type); + thickness = spring_washer_thickness(type); + diameter = spring_washer_diameter(type); + vitamin(str("spring_washer(", type[0], "_washer): Washer spring M", hole, " x ", thickness, "mm")); + ir = washer_id(type) / 2; + or = diameter / 2; + path = circle_points((ir + or) / 2, exploded() ? thickness / 2 : 0); + profile = rectangle_points(thickness, or - ir); + color(hard_washer_colour) + translate_z(thickness / 2) + rotate(180) + sweep(path, profile); + + if($children) + translate_z(thickness) + children(); +} + +module printed_washer(type, name = false) { //! Create printed washer + stl(name ? name : str("M", washer_size(type) * 10, "_washer")); + t = round_to_layer(washer_thickness(type)); + or = washer_radius(type); + ir = washer_id(type) / 2; + color(pp1_colour) + linear_extrude(height = t, center = false, convexity = 2) + poly_ring(or, ir); + + if($children) + translate_z(t) + children(); +} diff --git a/vitamins/washers.scad b/vitamins/washers.scad new file mode 100644 index 0000000..eae88d1 --- /dev/null +++ b/vitamins/washers.scad @@ -0,0 +1,53 @@ +// +// 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 . +// + +// +// Washers +// +// s d t s s s s p +// c i h o t p p e +// r a i f a r r n +// e m c t r i i n +// w e k n n y +// t n d g g +// e e i v +// r s a d t e +// s i h r +// a k +M3_penny_washer = ["M3_penny", 3, 12, 0.8, false, 5.8, 5.6, 1.0, true]; +M4_penny_washer = ["M4_penny", 4, 14, 0.8, false, 7.9, 7.0, 1.2, true]; +M5_penny_washer = ["M5_penny", 5, 20, 1.4, false, 9.0, 8.8, 1.6, true]; +M6_penny_washer = ["M6_penny", 6, 26, 1.5, false, 10.6, 9.9, 1.6, true]; +M8_penny_washer = ["M8_penny", 8, 30, 1.5, false, 13.8, 12.7, 2.0, true]; + +M2_washer = ["M2", 2, 5, 0.3, false, 4.5, 4.4, 0.5, undef]; +M2p5_washer = ["M2p5", 2.5, 5.9, 0.5, false, 5.4, 5.1, 0.6, undef]; +M3_washer = ["M3", 3, 7, 0.5, false, 5.8, 5.6, 1.0, M3_penny_washer]; +M3p5_washer = ["M3p5", 3.5, 8, 0.5, false, 6.9, 6.2, 1.0, undef]; +M4_washer = ["M4", 4, 9, 0.8, false, 7.9, 7.0, 1.2, M4_penny_washer]; +M5_washer = ["M5", 5, 10, 1.0, false, 9.0, 8.8, 1.6, M5_penny_washer]; +M6_washer = ["M6", 6, 12.5, 1.5, false, 10.6, 9.9, 1.6, M6_penny_washer]; +M8_washer = ["M8", 8, 17, 1.6, false, 13.8, 12.7, 2.0, M8_penny_washer]; +toggle_washer = ["toggle", 6.1,12, 0.6, false, 10, 0, 0, undef]; + +M3_rubber_washer= ["M3_rubber",3, 10, 1.5, true, 5.8, M3_penny_washer]; + +washers = [M2_washer, M2p5_washer, M3_washer, M3p5_washer, M4_washer, M5_washer, M6_washer, M8_washer, M3_rubber_washer]; + +use diff --git a/vitamins/wire.scad b/vitamins/wire.scad new file mode 100644 index 0000000..9550ece --- /dev/null +++ b/vitamins/wire.scad @@ -0,0 +1,76 @@ +// +// 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 . +// + +// +//! Wires. Just a BOM entry at the moment and cable bundle size fuctions for holes. See +//! . +// +include <../core.scad> +include + +module wire(color, strands, length, strand = 0.2) + vitamin(str(": Wire ", color, " ", strands, "/", strand, " length ",length, "mm")); + +module ribbon_cable(ways, length) + vitamin(str(": Ribbon cable ", ways, " way ", length, "mm")); + +// +// Cable sizes +// +function cable_wires(cable) = cable[0]; +function cable_wire_size(cable) = cable[1]; + +// numbers from http://mathworld.wolfram.com/CirclePacking.html +function cable_radius(cable) = ceil([0, 1, 2, 2.15, 2.41, 2.7, 3, 3, 3.3][cable_wires(cable)] * cable_wire_size(cable)) / 2; // radius of a bundle + +function wire_hole_radius(cable) = cable_radius(cable) + 0.5; + +// arrangement of bundle in flat cable clip +function cable_bundle(cable) = [[0,0], [1,1], [2,1], [2, 0.5 + sin(60)], [2,2], [3, 0.5 + sin(60)], [3,2]][cable_wires(cable)]; + +function cable_width(cable) = cable_bundle(cable)[0] * cable_wire_size(cable); // width in flat clip +function cable_height(cable) = cable_bundle(cable)[1] * cable_wire_size(cable); // height in flat clip + +module mouse_hole(cable, h = 100) { + r = wire_hole_radius(cable); + + rotate(90) slot(r, 2 * r, h = h); +} + +module cable_tie_holes(cable_r, h = 100) { + r = cnc_bit_r; + l = 3; + extrude_if(h) + for(side = [-1, 1]) + translate([0, side * (cable_r + r)]) + hull() + for(end = [-1, 1]) + translate([end * (l / 2 - r), 0]) + drill(r, 0); +} + +module cable_tie(cable_r, thickness) { + w = 2 * (cable_r + cnc_bit_r); + translate_z(thickness / 2) + rotate([-90, 0, 90]) + ziptie(small_ziptie, w / 2); +} + +//cable_tie_holes(6 / 2); +//cable_tie(6 / 2, 3); diff --git a/vitamins/ziptie.scad b/vitamins/ziptie.scad new file mode 100644 index 0000000..775a80f --- /dev/null +++ b/vitamins/ziptie.scad @@ -0,0 +1,53 @@ +// +// 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 . +// + +// +//! Cable zipties. +// + +include <../core.scad> +use <../utils/tube.scad> + +function ziptie_width(type) = type[1]; //! Width +function ziptie_thickness(type) = type[2]; //! Thickness +function ziptie_latch(type) = type[3]; //! Latch dimensions +function ziptie_colour(type) = type[4]; //! Colour +function ziptie_tail(type) = type[5]; //! The length without teeth + +module ziptie(type, r) +{ + latch = ziptie_latch(type); + length = ceil(2 * PI * r + ziptie_tail(type) + latch.z + 1); + len = length <= 100 ? 100 : length; + vitamin(str("ziptie(", type[0], ", ", r, "): Ziptie ", len, "mm min length")); + + angle = (r > latch.x / 2) ? asin((latch.x / 2) / r) - asin(ziptie_thickness(type) / latch.x) : 0; + color(ziptie_colour(type)) union() { + tube(ir = r, or = r + ziptie_thickness(type), h = ziptie_width(type)); + translate([0, -r, - latch.y / 2]) + rotate([90, 0, angle]) { + union() { + cube(latch); + + translate([latch.x / 2, latch.y / 2, (latch.z + 1) / 2]) + cube([ziptie_thickness(type), ziptie_width(type), latch.z + 1], center = true); + } + } + } +} diff --git a/vitamins/zipties.scad b/vitamins/zipties.scad new file mode 100644 index 0000000..a098987 --- /dev/null +++ b/vitamins/zipties.scad @@ -0,0 +1,27 @@ +// +// 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 . +// + +// [width, thickness, [latch_x, latch_y, latch_z], color, tail] +small_ziptie = ["small_ziptie", 2.5, 1.0, [4.7, 4.25, 3.0], "white", 25]; +ziptie_3mm = ["ziptie_3mm", 3.0, 1.0, [5.4, 5.44, 4.5], "white", 25]; +ziptie_3p6mm = ["ziptie_3p6mm", 3.6, 1.2, [6.4, 6.62, 4.7], "white", 25]; + +zipties = [small_ziptie, ziptie_3mm, ziptie_3p6mm]; + +use