Models

honeycomb-wall.scad

Source: honeycomb-wall.scad
// honeycomb-wall.scad: a parametric honeycomb storage wall.
//
// Fills a print bed with honeycomb cells, or builds a custom layout column
// by column, with optional gaps, solid cells and flat edges. Cell sizes come
// from hsw.scad, shared with the inserts and clips.

include <hsw.scad>

/* [Grid size] */
// Largest wall that fits the print bed (mm). The defaults suit a Bambu Lab
// A1 (about 10 x 10 cells); a Prusa i3 MK3 takes 240 x 208.
max_grid_width = 211;
max_grid_height = 248;

/* [Layout] */
// 0 fills the grid size; the others are column-by-column layouts
column_data_index = 0; // [0:Fill the grid size, 1:Example layout, 2:IKEA 365+ drybox filament end, 3:IKEA 365+ drybox other end]
// Cells in each column, left to right, for each layout
column_data = [
  [],
  [3, 5, 8, 6, 4, 3, 4, 5, 6],
  [7, 6, 5, 7, 7, 6, 5, 7],
  [4, 5, 4, 5, 4, 5, 4, 5],
];
// Start the half-cell stagger on the first column instead of the second
flip_staggering = true;

// Move columns up or down, in cells (custom layouts can then exceed the grid size)
include_offsets = false;
column_offsets = [0, -2, -3, -1, 0, 2, 4];

// Leave cells out: for each column, the rows to skip, counting from 1
include_gaps = false;
column_gaps = [[], [3, 4], [4, 5], [2]];

/* [Solid cells] */
// Close the front of chosen cells with a solid face. Tip: add solid_height to
// hsw_depth to keep the same insert depth behind it.
include_solids = false;
solid_height = 1;
// For each column, the rows to close, counting from 1
column_solids = [[], [], [for (i = [3:7]) i], [for (i = [2:7]) i]];

/* [Flat edges] */
edge_left = false;
edge_top = false;
edge_right = false;
edge_bottom = false;

$fn = $preview ? 32 : 64;

// ---------------- Layout ----------------
fill = column_data_index == 0;
columns = column_data[column_data_index];
// A flat edge cuts a cell in half, so it makes room for half a cell more.
half_x = (edge_left ? 0.5 : 0) + (edge_right ? 0.5 : 0);
half_y = (edge_top ? 0.5 : 0) + (edge_bottom ? 0.5 : 0);

column_count = fill ? floor(max_grid_width / hsw_pitch_x() + half_x) : len(columns);
// Rows in the unshifted columns, and in the columns shifted half a cell down
rows_even = fill ? floor(max_grid_height / hsw_pitch_y() + half_y) : max(columns);
rows_odd = fill ? floor(max_grid_height / hsw_pitch_y() - 0.5 + half_y) : max(columns) - 0.5;

// How far down the grid reaches, for trimming the bottom edge
grid_height = hsw_pitch_y() * max(rows_even - 0.5, rows_odd);

function shifted(col) = (col + (flip_staggering ? 1 : 0)) % 2;
function rows_in(col) = shifted(col) == 0 ? rows_even : rows_odd;
function listed(list, col, row) = col < len(list) && len(search(row + 1, list[col])) > 0;

// ---------------- Build ----------------
translate([edge_left ? 0 : hsw_cell_side(), edge_top ? 0 : -hsw_pitch_y() / 2, 0])
  for (col = [0:column_count - 1]) {
    n = fill ? rows_even : columns[col];
    lift = include_offsets && col < len(column_offsets) ? column_offsets[col] : 0;
    for (row = [0:n - 1])
      if (row < rows_in(col) && !(include_gaps && listed(column_gaps, col, row))) {
        y = -hsw_pitch_y() * (row + lift + shifted(col) / 2);
        last = row + 1 == rows_in(col);
        translate([hsw_pitch_x() * col, y, 0])
          wall_cell(
            left = edge_left && col == 0,
            top = edge_top && row == 0 && shifted(col) == 0,
            right = edge_right && col == column_count - 1,
            // only a last cell that runs past the bottom, centre still inside
            bottom = edge_bottom && last && hsw_pitch_y() - y > grid_height + 0.001 && hsw_pitch_y() / 2 - y <= grid_height,
            solid = include_solids && listed(column_solids, col, row)
          );
      }
  }

// A cell, cut in half and closed with a flat wall on each side that asks,
// and closed at the front if solid.
module wall_cell(left, top, right, bottom, solid) {
  h = hsw_pitch_y();
  d = 2 * hsw_cell_side();
  difference() {
    union() {
      hsw_cell();
      if (solid)
        translate([0, 0, hsw_depth - solid_height])
          linear_extrude(solid_height) hsw_hexagon(hsw_cell_flats());
      if (left) translate([0, -h / 2, 0]) hsw_edge_wall(h);
      if (right) translate([0, h / 2, 0]) rotate([0, 0, 180]) hsw_edge_wall(h);
      if (top) translate([-d / 2, 0, 0]) rotate([0, 0, -90]) hsw_edge_wall(d);
      if (bottom) translate([d / 2, 0, 0]) rotate([0, 0, 90]) hsw_edge_wall(d);
    }
    if (left) translate([-d / 2, -h, -1]) cube([d / 2, 2 * h, hsw_depth + 2]);
    if (right) translate([0, -h, -1]) cube([d / 2, 2 * h, hsw_depth + 2]);
    if (top) translate([-d / 2, 0, -1]) cube([d, h, hsw_depth + 2]);
    if (bottom) translate([-d / 2, -h, -1]) cube([d, h, hsw_depth + 2]);
  }
}

honeycomb-wall.scad on GitHub

attachments/hook.scad

Source: attachments/hook.scad
// hook.scad: a screw-on wall hook.
//
// A strip bent into a J: a back plate against the wall, a bend into a
// horizontal arm, and a bend up into the lip. The two free ends are rounded
// across the strip's width. Edges are filleted or chamfered.

/* [Size] */
// Back plate length, from the bend to the start of its rounded top (mm)
back_length = 90;
// Strip width (mm)
width = 60;
// Strip thickness (mm)
thickness = 15;
// Arm length between the two bends (mm)
arm_length = 40;
// Inside radius of both bends (mm)
bend_radius = 10;

/* [Edges] */
edge_style = "fillet"; // [fillet, chamfer]
// Fillet radius (mm)
fillet = 1;
// Chamfer size (mm)
chamfer = 3;

/* [Screws] */
// Screw hole diameter (mm)
screw_diameter = 6; // [5, 6, 8, 10]
// Countersink the holes on the hook side
countersink = false;

$fn = $preview ? 32 : 64;

// The strip's cross-section: x across the thickness, y across the width.
module section() {
  if (edge_style == "chamfer") {
    c = min(chamfer, thickness / 2 - 0.01, width / 2 - 0.01);
    polygon([[c, 0], [thickness - c, 0], [thickness, c], [thickness, width - c],
             [thickness - c, width], [c, width], [0, width - c], [0, c]]);
  } else {
    f = min(fillet, thickness / 2 - 0.01, width / 2 - 0.01);
    translate([f, f]) offset(r = f) square([thickness - 2 * f, width - 2 * f]);
  }
}

// A straight run of strip along +z, from z = 0 to len.
module run(len) {
  linear_extrude(len) section();
}

// A rounded end across the strip's width, standing on z = 0.
module rounded_end() {
  r = width / 2;
  if (edge_style == "chamfer") {
    c = min(chamfer, thickness / 2 - 0.01);
    intersection() {
      translate([0, r, 0]) rotate([0, 90, 0]) hull() {
        cylinder(r = r - c, h = thickness);
        translate([0, 0, c]) cylinder(r = r, h = thickness - 2 * c);
      }
      translate([0, 0, 0]) cube([thickness, width, r]);
    }
  } else {
    f = min(fillet, thickness / 2 - 0.01);
    intersection() {
      translate([f, r, 0]) rotate([0, 90, 0]) minkowski() {
        cylinder(r = r - f, h = thickness - 2 * f);
        sphere(f, $fn = 16);
      }
      cube([thickness, width, r]);
    }
  }
}

// A quarter bend of strip: the section swept 90 degrees about an axis along
// y, inside radius bend_radius.
module bend() {
  rotate([90, 0, 0]) rotate_extrude(angle = 90)
    translate([bend_radius, 0]) rotate(0) mirror([0, 1]) section();
}

module screw_holes() {
  for (z = [back_length / 3, back_length])
    translate([0, width / 2, z]) rotate([0, 90, 0]) {
      translate([0, 0, -1]) cylinder(d = screw_diameter, h = thickness + 2);
      if (countersink)
        translate([0, 0, -0.01]) cylinder(d1 = screw_diameter * 1.7, d2 = screw_diameter, h = thickness / 4);
    }
}

// The back plate stands at x = 0..thickness, wall side at x = thickness; the
// hook opens toward -x.
module hook() {
  r = bend_radius;
  difference() {
    union() {
      run(back_length);
      translate([0, 0, back_length]) rounded_end();
      // bend at the bottom of the back plate, into the arm
      translate([-r, 0, 0]) rotate([0, 0, 0]) mirror([0, 0, 1]) bend();
      // the arm, running toward -x
      translate([-r, 0, -r]) rotate([0, -90, 0]) translate([-thickness, 0, 0]) run(arm_length);
      // bend up into the lip
      translate([-r - arm_length, 0, 0]) rotate([0, 0, 180]) translate([0, -width, 0]) mirror([0, 0, 1]) bend();
      // the lip's rounded top
      translate([-2 * r - arm_length - thickness, 0, 0]) rounded_end();
    }
    screw_holes();
  }
  echo(str("Hook: ", back_length + width / 2 + r + thickness, " mm tall, ", arm_length + 2 * (r + thickness), " mm deep"));
}

hook();

attachments/hook.scad on GitHub

attachments/plier_holder.scad

Source: attachments/plier_holder.scad
use <rounded_triangle.scad>

$fn = $preview ? 32 : 64; // Smoothness of circles
z_fight = $preview ? 0.05 : 0; // Small offset to prevent z-fighting in preview mode

// =============================================================
// Parameters
// =============================================================
triangle_height = 25;
triangle_base = 14;
tip_diameter = 3;

length = 50;

screw_diameter = 3.5;

// =============================================================
// Main build
// =============================================================
difference() {
  // Extrude a rounded triangle
  translate([-triangle_base / 2, 0, 0])
    linear_extrude(height=length)
      rounded_triangle(triangle_base, triangle_height, tip_diameter);

  // Chamfer the bottom edges
  for (i = [0:1])
    mirror([i, 0, 0])
      translate([-triangle_base / 2, 0, length / 2])
        rotate([0, 0, 25])
          cube([triangle_base / 4, triangle_base / 2, length + z_fight], center=true);

  // Mass cut off at the bottom to reduce material use
  translate([0, 0, length / 2])
    scale([1, 2.5, 1])
      cylinder(h=length + z_fight, d=tip_diameter * 2, center=true, $fn=32);

  // Mass cut off at the bottom to reduce material use
  translate([0, triangle_height * 0.8, length / 2])
    scale([0.5, 2, 1])
      cylinder(h=length + z_fight, d=tip_diameter, center=true, $fn=32);

  // Head bore
  translate([0, triangle_height / 2, length / 2 + screw_diameter * 3])
    cylinder(h=length + z_fight, d=screw_diameter * 1.67, center=true, $fn=32);

  // Screw hole
  translate([0, triangle_height / 2, length / 2])
    cylinder(h=length + z_fight, d=screw_diameter, center=true, $fn=32);
}

attachments/plier_holder.scad on GitHub

attachments/tool_holder.scad

Source: attachments/tool_holder.scad
// tool_holder.scad: a screw-on rack of tool holders.
//
// A flange strip with a screw hole at each end carries a row of holders:
// angled hex pegs with a bore down the middle (for bits, spokes or anything
// slim), or rings that hold a screwdriver by its shank.

/* [Rack] */
// What the rack holds
holder = "peg"; // [peg, ring]
// Number of holders
count = 8;
// Distance from the first holder to the last (mm)
span = 142;

/* [Flange] */
flange_height = 10;
flange_thickness = 3;
// Screw hole diameter (mm)
mount_hole = 5;

/* [Pegs] */
// Across corners of the hex peg (mm)
peg_diameter = 6;
peg_length = 40;
// Upward tilt from horizontal (degrees)
peg_tilt = 15;
// Bore down the peg's axis (mm)
peg_bore = 2.5;

/* [Rings] */
// Shank hole (mm)
ring_hole = 11;
ring_wall = 3;
// Ring height (mm)
ring_height = 12;
// Gap between the ring and the flange (mm)
ring_standoff = 15;

$fn = $preview ? 32 : 64;

pitch = count > 1 ? span / (count - 1) : 0;
flange_length = span + max(holder == "ring" ? ring_hole + 2 * ring_wall : peg_diameter, 0) + 4 * mount_hole;

// The flange lies in the XZ plane, wall side at y = 0 and holder side at
// y = -flange_thickness; holders stand out toward -y.
module flange() {
  difference() {
    translate([-flange_length / 2, -flange_thickness, -flange_height / 2])
      cube([flange_length, flange_thickness, flange_height]);
    for (s = [-1, 1])
      translate([s * (flange_length / 2 - mount_hole), 1, 0]) rotate([90, 0, 0])
        cylinder(d = mount_hole, h = flange_thickness + 2);
  }
}

// A hex peg rising at peg_tilt from the flange face, its root cut flush with
// the flange so it sits flat on it.
module peg() {
  difference() {
    rotate([90 - peg_tilt, 0, 0]) rotate([0, 0, 30]) translate([0, 0, -peg_diameter])
      cylinder(d = peg_diameter, h = peg_length + peg_diameter, $fn = 6);
    rotate([90 - peg_tilt, 0, 0]) translate([0, 0, -peg_diameter - 1])
      cylinder(d = peg_bore, h = peg_length + peg_diameter + 2);
    // keep only what stands in front of the flange face
    translate([-peg_diameter, 0, -2 * peg_length]) cube([2 * peg_diameter, 2 * peg_length, 4 * peg_length]);
  }
}

// A ring for a screwdriver shank, on an arm out from the flange.
module ring() {
  od = ring_hole + 2 * ring_wall;
  y = -(ring_standoff + od / 2);
  difference() {
    union() {
      translate([0, y, -ring_height / 2]) cylinder(d = od, h = ring_height);
      translate([-ring_wall, y, -ring_height / 2]) cube([2 * ring_wall, -y, ring_height]);
    }
    translate([0, y, -ring_height / 2 - 1]) cylinder(d = ring_hole, h = ring_height + 2);
  }
}

module tool_rack() {
  union() {
    flange();
    for (i = [0:count - 1])
      translate([-span / 2 + i * pitch, -flange_thickness, 0])
        if (holder == "ring") ring(); else peg();
  }
}

tool_rack();

attachments/tool_holder.scad on GitHub

hsw-clips/hsw_clip.scad

Source: hsw-clips/hsw_clip.scad
include <BOSL2/std.scad>
include <BOSL2/rounding.scad>
include <BOSL2_utils.scad>
include <hswx.scad>

$fn = $preview ? 32 : 64;

generate_clipconnector = false;
generate_clip = true;
generate_clip_rect_base = false;
generate_clip_hex_base = false;

// A double clip to hold two pieces of HSW together
module hsw_clipconnector(
  slop = 0, // some extra gap so the fit is not so tight
  rectbase = 0, // put a rectangular base on top and give it a height
  hexbase = 0 // put a hexbase on top and give it a height
) {

  bridge_x = hswx_outside - hswx_inside;
  bridge_y = (hswx_inside / 2) - slop;

  difference() {
    union() {
      // two clips with base
      hsw_clip(center=true, rotate=180, type=0, rectbase=rectbase, slop=slop, hexbase=hexbase);
      translate([hswx_outside, 0, 0])
        hsw_clip(center=true, rotate=0, type=0, rectbase=rectbase, slop=slop, hexbase=hexbase);
      translate([hswx_outside / 2 - bridge_x / 2, -bridge_y / 2, 0])
        cube([bridge_x, bridge_y, height]);
    }

    height = max(rectbase, hexbase);

    // carve out the stress-reliever between them to bend
    translate([hswx_outside / 2, hswx_inside / 2, height])
      rotate([90, 0, 0])
        cylinder(h=hswx_inside, d=height);
  }
}

plug_base_thickness = 1;
plug_base_lip = 1;
plug_stud_thickness = 1.7;
plug_stud_height = hswx_lock_depth - 2;
plug_spring_base = 3;
plug_spring_depth = 5;
plug_spring_thickness = 1.4;

module hsw_clip(
  center = false, // center or start from [0,0,0]
  rotate = 0, // rotate result
  type = 0, // type not used -- may someday specify weak v. strong directional
  hexbase = 0, // put a hexbase on top and give it a height
  rectbase = 0, // put a rectangular base on top and give it a height
  slop = 0
) // introduce slop to clip length if too tight
{
  hswx_inside = hswx_inside - slop;
  outline = [
    [
      [-plug_base_lip, 0],
      [slop, 0, 0.1], // origin
      [slop, hswx_lock_depth], // strong-side base
      [-hswx_lock_lip, hswx_lock_lip + hswx_lock_depth, 0.5], // strong lock

      [-hswx_lock_lip, hswx_depth, 1.5],

      [plug_stud_thickness, hswx_depth], // spring
      [plug_spring_base, hswx_depth, 3.5],
      [hswx_inside / 2, hswx_depth - plug_spring_depth - 0.5, 5.0], // upper spring midpoint
      [hswx_inside - plug_spring_base, hswx_depth, 3.5],
      [hswx_inside - plug_stud_thickness, hswx_depth],

      [hswx_inside, hswx_depth, 2.0], // weak lock
      [hswx_inside + hswx_lock_lip, hswx_lock_depth + hswx_lock_lip, 0.5],
      [hswx_inside, hswx_lock_depth], // weak-side base
      [hswx_inside, 0.1, 0.1],
      [hswx_inside + 0.1, 0],
      [hswx_inside - plug_stud_thickness - 0.5, 0],
      [hswx_inside - plug_stud_thickness, 0.5, 1.0],
      /**/
      [hswx_inside - plug_stud_thickness, hswx_depth - plug_spring_thickness - 1.4, 1.5],
      [hswx_inside - plug_spring_base + .1, hswx_depth - plug_spring_thickness - 0.1, 1.0],

      [hswx_inside / 2, hswx_depth - plug_spring_depth - plug_spring_thickness, 6.0],

      [plug_spring_base, hswx_depth - plug_spring_thickness, 2.0],
      [plug_stud_thickness, hswx_depth / 3, 1.0],
      [hswx_inside / 3.4, 0],
      [plug_stud_thickness, 0],
    ],
  ];

  translate(center ? [0, 0, 0] : [hswx_inside / 2, hswx_inside / 4, 0])
    rotate([0, 0, rotate])
      union() {
        translate([-hswx_inside / 2, -hswx_inside / 4, 0])
          rotate([-90, 0, 0])
            linear_extrude(hswx_inside / 2)
              polygon(round_corners(path=points(outline[type]), radius=rads(outline[type]), $fn=90));
        if (hexbase) {
          cyl(l=hexbase, d=hswx_od - 1, $fn=6, anchor=BOTTOM, spin=30, rounding2=hexbase / 2);
        }
        if (rectbase) {
          //rounding
          cuboid(size=[hswx_outside, hswx_inside / 2, rectbase], rounding=rectbase / 2, edges=[TOP + LEFT, TOP + RIGHT], anchor=BOTTOM + CENTER);
        }
      }
}

// hsw_clip(center=true, rotate=0); //, type=0, hexbase=3);
if (generate_clipconnector)
  rotate([90, 0, 0])
    hsw_clipconnector(slop=0.05, rectbase=generate_clip_rect_base ? 3 : 0, hexbase=generate_clip_hex_base ? 3 : 0);

if (generate_clip)
  hsw_clip(center=true, rectbase=generate_clip_rect_base ? 3 : 0, hexbase=generate_clip_hex_base ? 3 : 0);

hsw-clips/hsw_clip.scad on GitHub


This site uses Just the Docs, a documentation theme for Jekyll.