improve clip in strength
This commit is contained in:
1 parent
773a4d40ff
commit
6737bd36a0
1 file changed
+109
-83
@@ -8,12 +8,12 @@
|
|||||||
cases = 4;
|
cases = 4;
|
||||||
// Inner size of each compartment: X * X * X (mm)
|
// Inner size of each compartment: X * X * X (mm)
|
||||||
X = 20;
|
X = 20;
|
||||||
// Text engraved on the lid
|
// Text engraved on the lid (runs parallel to the sliding direction)
|
||||||
engraving = "Monday";
|
engraving = "Monday";
|
||||||
|
|
||||||
/* [Engraving] */
|
/* [Engraving] */
|
||||||
text_size = 6;
|
text_size = 6;
|
||||||
text_depth = 0.6;
|
text_depth = 0.6; // engraved with sloped walls (see dt_ang)
|
||||||
text_font = "Overpass:style=Bold";
|
text_font = "Overpass:style=Bold";
|
||||||
|
|
||||||
/* [Structure] */
|
/* [Structure] */
|
||||||
@@ -21,33 +21,39 @@ wall = 3.2; // outer side walls and front wall
|
|||||||
divider = 1.6; // wall between compartments
|
divider = 1.6; // wall between compartments
|
||||||
floor_t = 1.6; // floor thickness
|
floor_t = 1.6; // floor thickness
|
||||||
lid_h = 3.0; // lid thickness
|
lid_h = 3.0; // lid thickness
|
||||||
rail_ledge = 2.4; // width of the ledge the lid edges rest on (< wall)
|
rail_ledge = 1.4; // width of the ledge the lid edges rest on (< wall)
|
||||||
end_wall = 5.5; // rear wall thickness (holds the clip groove)
|
end_wall = 5.5; // rear wall thickness (holds the clip groove)
|
||||||
corner_r = 1.5; // vertical corner rounding
|
corner_r = 1.5; // vertical corner rounding
|
||||||
|
|
||||||
/* [Tolerances] */
|
/* [Dovetail] */
|
||||||
// Sliding clearance between lid and box
|
// Angle of the sliding faces from vertical = worst overhang of the print.
|
||||||
|
// 30 prints cleanly without supports; lower = even safer but less grip.
|
||||||
|
dt_ang = 30; // [15:1:45]
|
||||||
|
|
||||||
|
/* [Fit] */
|
||||||
|
// Sliding clearance between lid and box (PETG: 0.2 - 0.3)
|
||||||
tol = 0.25;
|
tol = 0.25;
|
||||||
// Clearance inside the snap pockets (smaller = tighter, less rattle)
|
// Clearance inside the snap pockets (smaller = tighter, less rattle)
|
||||||
snap_tol = 0.15;
|
snap_tol = 0.15;
|
||||||
|
|
||||||
/* [Snap] */
|
/* [Snap] */
|
||||||
|
// Length of the slots in the lid = length of the flexible tab and arms.
|
||||||
|
clip_len = 11.4;
|
||||||
// Rear bump: how far it is pushed aside while sliding (click strength)
|
// Rear bump: how far it is pushed aside while sliding (click strength)
|
||||||
detent = 0.7;
|
detent = 0.5;
|
||||||
// Side bumps: same, but sideways
|
// Side ridges: same, but sideways
|
||||||
side_detent = 0.6;
|
side_detent = 0.5;
|
||||||
// Side bump length along the lid face
|
// Flexible tab (rear bump): width, thickness, slot width
|
||||||
side_len = 1.8;
|
clip_w = 5;
|
||||||
// Flexible tab (rear bump): width, max length, slot width
|
tab_t = 1.2; // thinner = softer (the underside of the tab is relieved)
|
||||||
clip_w = 4.5;
|
|
||||||
clip_len_max = 28;
|
|
||||||
clip_slot = 1.0;
|
clip_slot = 1.0;
|
||||||
// Flexible side arms: thickness (stiffness) and slot width
|
// Flexible side arms: thickness (stiffness) and slot width, both measured
|
||||||
arm_t = 1.6;
|
// perpendicular to the sloped faces
|
||||||
|
arm_t = 1.2;
|
||||||
arm_slot = 1.2;
|
arm_slot = 1.2;
|
||||||
|
|
||||||
/* [Display] */
|
/* [Display] */
|
||||||
// plate = both parts laid out for printing, assembly = closed for preview
|
// plate = both parts laid out for printing, assembly = closed, for preview
|
||||||
part = "plate"; // [plate, box, lid, assembly]
|
part = "plate"; // [plate, box, lid, assembly]
|
||||||
// Assembly preview only: push the lid open by this many mm
|
// Assembly preview only: push the lid open by this many mm
|
||||||
lid_offset = 0;
|
lid_offset = 0;
|
||||||
@@ -58,6 +64,9 @@ lid_offset = 0;
|
|||||||
$fn = 48;
|
$fn = 48;
|
||||||
eps = 0.01;
|
eps = 0.01;
|
||||||
|
|
||||||
|
m = tan(dt_ang); // sideways shift per mm of height
|
||||||
|
cs = cos(dt_ang);
|
||||||
|
|
||||||
W = X + 2*wall; // outer width (Y)
|
W = X + 2*wall; // outer width (Y)
|
||||||
x_cav_end = wall + cases*X + (cases-1)*divider; // end of last compartment
|
x_cav_end = wall + cases*X + (cases-1)*divider; // end of last compartment
|
||||||
L = x_cav_end + end_wall; // outer length (X)
|
L = x_cav_end + end_wall; // outer length (X)
|
||||||
@@ -65,35 +74,43 @@ z0 = floor_t + X; // top of compartments
|
|||||||
hg = lid_h + tol; // height of the lid groove
|
hg = lid_h + tol; // height of the lid groove
|
||||||
H = z0 + hg; // total height
|
H = z0 + hg; // total height
|
||||||
gb = X/2 + rail_ledge; // groove half width at z0
|
gb = X/2 + rail_ledge; // groove half width at z0
|
||||||
k45 = tol*sqrt(2); // horizontal offset = tol on a 45 deg face
|
k = tol/cs; // horizontal gap = tol on the sloped faces
|
||||||
lw_b = gb - tol - k45; // lid half width at its bottom
|
lw_b = gb - m*tol - k; // lid half width at its bottom
|
||||||
lw_t = gb - hg - k45; // lid half width at its top
|
lw_t = gb - m*hg - k; // lid half width at its top
|
||||||
|
d1 = arm_t/cs; // horizontal offsets of the arm slot
|
||||||
|
d2 = (arm_t + arm_slot)/cs; // walls from the sloped face
|
||||||
|
|
||||||
lid_x0 = wall + tol; // lid front (closed position)
|
lid_x0 = wall + tol; // lid front (closed position)
|
||||||
lid_len = L - lid_x0; // lid rear is flush with box rear
|
lid_len = L - lid_x0; // lid rear is flush with box rear
|
||||||
clip_len = min(clip_len_max, lid_len*0.45); // tab and arm length
|
tab_r = lid_h - tab_t; // relief under the tab (softens it)
|
||||||
|
|
||||||
|
// Engraving: shrink the text if it would not fit between the lid front
|
||||||
|
// and the slots (average bold glyph is ~0.9 * text_size wide, conservative)
|
||||||
|
text_zone = lid_len - clip_len - 2*2; // 2 mm margin at both ends
|
||||||
|
text_fit = min(text_size, text_zone/(len(engraving)*0.9));
|
||||||
|
|
||||||
bump_h = tol + detent; // rear V bump height
|
bump_h = tol + detent; // rear V bump height
|
||||||
sb_h = tol + side_detent; // side bump height
|
sb_h = tol + side_detent; // side ridge height
|
||||||
cham = detent + tol; // lead-in chamfer on rear wall
|
cham = detent + tol; // lead-in chamfer on rear wall
|
||||||
xb = x_cav_end + (end_wall - cham)/2; // x of all detents
|
xb = x_cav_end + (end_wall - cham)/2; // x of all detents
|
||||||
|
zm = tol + lid_h/2; // mid height of the lid faces
|
||||||
// Height (above z0) of the side bump centre on the sloped lid face, chosen so that bump and dimple stay clear of the groove bottom and of the rail top
|
|
||||||
sb_hl = side_len/2 + snap_tol;
|
|
||||||
sb_up = sqrt(0.5)*(sb_hl + sb_h + snap_tol);
|
|
||||||
sb_dn = sqrt(0.5)*(sb_hl + 0.2 + snap_tol);
|
|
||||||
zs_lo = 0.15 + sb_dn;
|
|
||||||
zs_hi = hg - 0.35 - sb_up;
|
|
||||||
zs = (zs_lo + zs_hi)/2;
|
|
||||||
|
|
||||||
assert(cases >= 1, "cases must be >= 1");
|
assert(cases >= 1, "cases must be >= 1");
|
||||||
assert(rail_ledge < wall, "rail_ledge must be smaller than wall");
|
assert(dt_ang >= 15 && dt_ang <= 45, "dt_ang must be between 15 and 45");
|
||||||
assert(zs_lo <= zs_hi, "Lid too thin for the side bumps: increase lid_h or reduce side_len / side_detent");
|
assert(rail_ledge < wall - 1, "rail_ledge must be at least 1 mm smaller than wall");
|
||||||
|
assert(m*lid_h - k >= 1, "Dovetail grip too small: increase lid_h or dt_ang");
|
||||||
assert(arm_slot > side_detent + 0.2, "arm_slot must exceed side_detent + 0.2");
|
assert(arm_slot > side_detent + 0.2, "arm_slot must exceed side_detent + 0.2");
|
||||||
assert(clip_w/2 + clip_slot + 1.2 < lw_t - (arm_t + arm_slot)*sqrt(2),
|
assert(lw_t - d2 - (clip_w/2 + clip_slot) >= 1.2,
|
||||||
"Tab, slots and side arms do not fit in the lid (X is too small, about 20 mm minimum with default settings): decrease clip_w / clip_slot / arm_t / arm_slot or increase X");
|
"Tab, slots and side arms do not fit in the lid (X too small, about 18 mm minimum with default settings): reduce clip_w / clip_slot / arm_t / arm_slot or increase X");
|
||||||
|
assert(tab_t >= 0.8 && tab_t <= lid_h, "tab_t must be between 0.8 and lid_h");
|
||||||
|
assert(lid_len >= clip_len + 8, "Lid too short for this clip_len: reduce clip_len");
|
||||||
|
assert(text_zone > 4, "Lid too short for any engraving: reduce clip_len");
|
||||||
|
|
||||||
echo(str("Outer size: ", L, " x ", W, " x ", H, " mm"));
|
echo(str("Outer size: ", L, " x ", W, " x ", H, " mm"));
|
||||||
|
if (text_fit < text_size)
|
||||||
|
echo(str("Engraving scaled down from size ", text_size, " to ", text_fit));
|
||||||
|
if (text_fit < 3)
|
||||||
|
echo("WARNING: engraving is very small; use fewer characters, more cases or a shorter clip_len");
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Helpers
|
// Helpers
|
||||||
@@ -102,7 +119,7 @@ echo(str("Outer size: ", L, " x ", W, " x ", H, " mm"));
|
|||||||
module yz_extrude(len) {
|
module yz_extrude(len) {
|
||||||
rotate([90, 0, 90]) linear_extrude(height = len) children();
|
rotate([90, 0, 90]) linear_extrude(height = len) children();
|
||||||
}
|
}
|
||||||
// Extrude a 2D (x,z) profile along Y, centered on y = 0
|
// Extrude a 2D (x,z) profile along Y, centred on y = 0
|
||||||
module xz_extrude(w) {
|
module xz_extrude(w) {
|
||||||
rotate([90, 0, 0]) linear_extrude(height = w, center = true) children();
|
rotate([90, 0, 0]) linear_extrude(height = w, center = true) children();
|
||||||
}
|
}
|
||||||
@@ -110,27 +127,20 @@ module rrect(l, w, r) {
|
|||||||
translate([0, -w/2]) offset(r = r) offset(delta = -r) square([l, w]);
|
translate([0, -w/2]) offset(r = r) offset(delta = -r) square([l, w]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Side bump
|
// Side ridge profile: x = sliding direction, y = face normal.
|
||||||
module side_bump_3d(extra = 0) {
|
// It runs along the whole sloped face (no end faces -> no overhang).
|
||||||
h = sb_h + extra;
|
module side_bump_2d() {
|
||||||
len = side_len + extra*2;
|
polygon([[-sb_h, -0.3], [sb_h, -0.3], [sb_h, 0], [0, sb_h], [-sb_h, 0]]);
|
||||||
|
|
||||||
// Pyramid pointing outwards in local +Y
|
|
||||||
rotate([-90, 0, 0])
|
|
||||||
scale([1, len/(2*h), 1])
|
|
||||||
cylinder(h = h, r1 = h, r2 = 0, $fn = 4);
|
|
||||||
|
|
||||||
// Embedded base
|
|
||||||
translate([0, -0.2, 0])
|
|
||||||
rotate([-90, 0, 0])
|
|
||||||
scale([1, len/(2*h), 1])
|
|
||||||
cylinder(h = 0.2, r1 = h, r2 = h, $fn = 4);
|
|
||||||
}
|
}
|
||||||
|
module side_prism(grow = 0) {
|
||||||
|
linear_extrude(height = hg/cs + 4, center = true)
|
||||||
|
offset(delta = grow) side_bump_2d();
|
||||||
|
}
|
||||||
|
// Place children on the middle of the lid's sloped face
|
||||||
module on_side(s) { // s = +1 right side, -1 left side
|
module on_side(s) { // s = +1 right side, -1 left side
|
||||||
translate([xb, s*(lw_b - (zs - tol)), z0 + zs])
|
translate([xb, s*(gb - m*zm - k), z0 + zm])
|
||||||
if (s > 0) rotate([45, 0, 0]) children();
|
if (s > 0) rotate([dt_ang, 0, 0]) children();
|
||||||
else mirror([0, 1, 0]) rotate([45, 0, 0]) children();
|
else mirror([0, 1, 0]) rotate([dt_ang, 0, 0]) children();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
@@ -149,8 +159,8 @@ module box() {
|
|||||||
translate([wall, 0, z0])
|
translate([wall, 0, z0])
|
||||||
yz_extrude(L - wall + eps)
|
yz_extrude(L - wall + eps)
|
||||||
polygon([[-gb, 0], [gb, 0],
|
polygon([[-gb, 0], [gb, 0],
|
||||||
[ gb - hg - eps, hg + eps],
|
[ gb - m*(hg + eps), hg + eps],
|
||||||
[-(gb - hg - eps), hg + eps]]);
|
[-(gb - m*(hg + eps)), hg + eps]]);
|
||||||
|
|
||||||
// V groove in the rear wall for the tab bump
|
// V groove in the rear wall for the tab bump
|
||||||
translate([xb, 0, 0])
|
translate([xb, 0, 0])
|
||||||
@@ -160,9 +170,11 @@ module box() {
|
|||||||
[ bump_h, z0 + tol],
|
[ bump_h, z0 + tol],
|
||||||
[ 0, z0 + tol - bump_h]]);
|
[ 0, z0 + tol - bump_h]]);
|
||||||
|
|
||||||
// dimples in the rails for the side bumps
|
// V channels along the rail faces for the side ridges
|
||||||
for (s = [-1, 1]) on_side(s)
|
intersection() {
|
||||||
side_bump_3d(snap_tol);
|
union() for (s = [-1, 1]) on_side(s) side_prism(snap_tol);
|
||||||
|
translate([xb - 5, -W, z0]) cube([10, 2*W, hg + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
// lead-in chamfer so the tab bump can climb onto the rear wall
|
// lead-in chamfer so the tab bump can climb onto the rear wall
|
||||||
xz_extrude(X)
|
xz_extrude(X)
|
||||||
@@ -173,48 +185,65 @@ module box() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Engraving
|
||||||
|
engr_slices = 6;
|
||||||
|
module engraving_cut(tx) {
|
||||||
|
dz = text_depth/engr_slices;
|
||||||
|
for (i = [0 : engr_slices - 1])
|
||||||
|
translate([tx, 0, z0 + hg - (i + 1)*dz])
|
||||||
|
linear_extrude(dz + eps)
|
||||||
|
offset(delta = -i*dz*tan(dt_ang))
|
||||||
|
text(engraving, size = text_fit, font = text_font,
|
||||||
|
halign = "center", valign = "center");
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Lid
|
// Lid (modelled in its closed position, engraved face up)
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
module lid(bumps = true) {
|
module lid(bumps = true) {
|
||||||
text_x = (lid_x0 + L - clip_len)/2;
|
text_x = (lid_x0 + L - clip_len)/2;
|
||||||
d1 = arm_t*sqrt(2);
|
|
||||||
d2 = (arm_t + arm_slot)*sqrt(2);
|
|
||||||
za = tol - 1;
|
za = tol - 1;
|
||||||
zb = hg + 1;
|
zb = hg + 1;
|
||||||
// x-offset of the side face at height z (right side)
|
// y of the right sloped face, moved inwards by d (horizontal), at height z
|
||||||
function yf(z, d) = lw_b - (z - tol) - d;
|
function yf(z, d) = lw_b - m*(z - tol) - d;
|
||||||
|
|
||||||
difference() {
|
difference() {
|
||||||
union() {
|
union() {
|
||||||
// lid plate (dovetail profile)
|
// lid plate (dovetail profile), underside of the tab relieved
|
||||||
translate([lid_x0, 0, z0])
|
difference() {
|
||||||
yz_extrude(lid_len)
|
translate([lid_x0, 0, z0])
|
||||||
polygon([[-lw_b, tol], [lw_b, tol],
|
yz_extrude(lid_len)
|
||||||
[ lw_t, hg], [-lw_t, hg]]);
|
polygon([[-lw_b, tol], [lw_b, tol],
|
||||||
|
[ lw_t, hg], [-lw_t, hg]]);
|
||||||
|
translate([L - clip_len, -(clip_w/2 + clip_slot), z0 + tol - 1])
|
||||||
|
cube([clip_len + 1, clip_w + 2*clip_slot, 1 + tab_r]);
|
||||||
|
}
|
||||||
|
|
||||||
if (bumps) {
|
if (bumps) {
|
||||||
// V bump under the free end of the tab
|
// V bump under the free end of the tab (45 deg flanks, grows
|
||||||
|
// from the relieved underside, apex at the same height as before)
|
||||||
translate([xb, 0, 0])
|
translate([xb, 0, 0])
|
||||||
xz_extrude(clip_w)
|
xz_extrude(clip_w)
|
||||||
polygon([[-bump_h, z0 + tol + eps],
|
polygon([[-(bump_h + tab_r), z0 + tol + tab_r + eps],
|
||||||
[ bump_h, z0 + tol + eps],
|
[ bump_h + tab_r, z0 + tol + tab_r + eps],
|
||||||
[ 0, z0 + tol - bump_h]]);
|
[ 0, z0 + tol - bump_h]]);
|
||||||
|
// side ridges, cut flush with the lid top and bottom planes
|
||||||
// side bumps on the flexible arms
|
intersection() {
|
||||||
for (s = [-1, 1]) on_side(s)
|
union() for (s = [-1, 1]) on_side(s) side_prism(0);
|
||||||
side_bump_3d(0);
|
translate([xb - 5, -W/2, z0 + tol]) cube([10, W, lid_h]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// slots that free the central tab
|
// slots that free the central tab (vertical walls)
|
||||||
for (s = [-1, 1])
|
for (s = [-1, 1])
|
||||||
translate([L - clip_len,
|
translate([L - clip_len,
|
||||||
s*(clip_w/2 + clip_slot/2) - clip_slot/2,
|
s*(clip_w/2 + clip_slot/2) - clip_slot/2,
|
||||||
z0 - 1])
|
z0 - 1])
|
||||||
cube([clip_len + 1, clip_slot, hg + 2]);
|
cube([clip_len + 1, clip_slot, hg + 2]);
|
||||||
|
|
||||||
// slots (parallel to the sloped faces) that free the side arms
|
// slots that free the side arms, parallel to the sloped faces so the
|
||||||
|
// arms keep a constant thickness (same angle as the dovetail)
|
||||||
for (s = [-1, 1])
|
for (s = [-1, 1])
|
||||||
translate([L - clip_len, 0, z0])
|
translate([L - clip_len, 0, z0])
|
||||||
yz_extrude(clip_len + 1)
|
yz_extrude(clip_len + 1)
|
||||||
@@ -223,10 +252,7 @@ module lid(bumps = true) {
|
|||||||
[yf(zb, d2), zb], [yf(za, d2), za]]);
|
[yf(zb, d2), zb], [yf(za, d2), za]]);
|
||||||
|
|
||||||
// engraving, parallel to the sliding direction
|
// engraving, parallel to the sliding direction
|
||||||
translate([text_x, 0, z0 + hg - text_depth])
|
engraving_cut(text_x);
|
||||||
linear_extrude(text_depth + eps)
|
|
||||||
text(engraving, size = text_size, font = text_font,
|
|
||||||
halign = "center", valign = "center");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,4 +274,4 @@ if (part == "plate") {
|
|||||||
} else if (part == "assembly") {
|
} else if (part == "assembly") {
|
||||||
box();
|
box();
|
||||||
translate([lid_offset, 0, 0]) lid();
|
translate([lid_offset, 0, 0]) lid();
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user