Last active
January 28, 2021 19:04
-
-
Save psmay/f8ecd3fa2f9ebc94dd2bb58d582c5960 to your computer and use it in GitHub Desktop.
MPMD Magnetic Bed Clip plus way too many parameters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
MPMD Magnetic Bed Clip plus way too many parameters | |
Copyright © 2021 Peter S. May | |
Based on MPMD adjustable magnetic bed clip v6 by ksihota | |
https://www.thingiverse.com/thing:3412636 | |
Licensed under Creative Commons - Attribution 4.0 | |
https://creativecommons.org/licenses/by/4.0/ | |
See this as a Gist: | |
https://gist.github.com/psmay/f8ecd3fa2f9ebc94dd2bb58d582c5960 | |
- - - - - | |
This version is from 2021-01-28. | |
This is one of my first public outings with OpenSCAD, and I hope it's as | |
educational for you as it has been for me. | |
A few of the numbers are guessed, but this should be a reasonable facsimile | |
of the source material. The shape of the stub in the center where the screw | |
goes was particularly mystifying, but I think I've guessed it correctly. | |
* 2021-01-28: | |
* Several parameters have been reworked to make more sense to the | |
casual adjuster. Many smaller adjustments now just make sense | |
without having to make separate adjustments elsewhere. Some | |
values that should have been coupled together now are. | |
* In particular, the tube capacity can be defined directly | |
using inner height and inner diameter, and it (mostly) Just | |
Works. Previously, adjusting the inner diameters also | |
required adjustments to the outer diameters, the base size, | |
the tube center spacing, and so forth. | |
* If you need to increase the tube diameter past about | |
16.75, you'll probably need to raise the tube center | |
position as well; otherwise the tubes start to overtake | |
the tab on the front of the base. (NB: This size of | |
magnet may leave your print bed area a little crowded | |
anyway.) | |
* Manual formatting improvements. | |
* Light renaming. | |
* 2021-01-27: Initial. | |
*/ | |
/* [Floor] */ | |
floor_thickness_outside_tubes = 2; | |
floor_thickness_inside_tubes = 0.8; | |
/* [Front tab] */ | |
tab_hole_diameter = 4.75; | |
// Distance from edge of tab to edge of tab hole | |
tab_hole_inset = 0; | |
tab_length = 6; | |
tab_width = 10; | |
tab_corner_radius = 4; | |
/* [Magnet tubes] */ | |
// Y position of the centers of the magnet tubes | |
tube_center_position = 5; | |
tube_inner_height = 7.2; | |
tube_inner_diameter = 12.75; | |
tube_wall_thickness = 1.625; | |
// Distance between the facing edges of the magnet tubes | |
tube_edge_spacing = 10; | |
/* [Clip holes in magnet tubes] */ | |
tube_clip_hole_diameter = 1.75; | |
tube_clip_hole_z = 6.5; | |
tube_clip_hole_max_depth = 3; | |
// Position of center of first clip hole, relative to tube center | |
tube_clip_hole_start_position = -1; | |
tube_clip_hole_count = 4; | |
tube_clip_hole_center_spacing = 2.5; | |
/* [Adjustment screw stub] */ | |
stub_height = 3; | |
stub_width = 7; | |
// Front-to-back length | |
stub_outer_diameter = 10; | |
// Gap between front of stub and main base front | |
stub_inset = 0; | |
stub_cylinder_chamfer_height = 2; | |
stub_cylinder_chamfer_width = 1; | |
stub_box_chamfer_height = 1.25; | |
stub_box_chamfer_width = 1; | |
stub_front_slope = 0.333333333333; | |
// Z intercept of front slope, relative to the top of the stub | |
stub_front_z_intercept = 0.166666666667; | |
// Width of stub top projection | |
stub_proj_width = 3; | |
// Length of square part of stub top projection | |
stub_proj_length = 2; | |
// Length of pointed part of stub top projection | |
stub_proj_point_length = 6; | |
/* [Adjustment screw and nut] */ | |
screw_hole_diameter = 3.25; | |
// Nut recess diameter, measured across opposite corners | |
nut_recess_diameter = 6.6; | |
nut_recess_depth = 3; | |
/* [Quality parameters] */ | |
$fa = 6; | |
$fs = 0.07; | |
// Small amount added to certain dimensions to ensure that adjacent solids are treated as intersecting | |
q = 0.001; | |
/* Computed values */ | |
tube_outer_diameter = tube_inner_diameter + (2 * tube_wall_thickness); | |
tube_center_spacing = tube_edge_spacing + tube_outer_diameter; | |
base_width = tube_center_spacing + tube_outer_diameter; | |
base_back_corner_radius = tube_outer_diameter / 2; | |
base_main_front_position = (-stub_outer_diameter / 2) - stub_inset; | |
base_front_corner_radius = tube_center_position - base_main_front_position; | |
stub_height_including_base = stub_height + floor_thickness_outside_tubes; | |
tube_clip_hole_start_y = tube_center_position + tube_clip_hole_start_position; | |
stub_proj_point = stub_proj_length + stub_proj_point_length; | |
tube_full_height = tube_inner_height + floor_thickness_inside_tubes; | |
color([1, 0, 0]) | |
difference() | |
{ | |
union() | |
{ | |
// The base and tab, including the tab hole. | |
linear_extrude(floor_thickness_outside_tubes) | |
full_base_2d(); | |
// The outer part of the magnet tubes. | |
translate([0, 0, q]) | |
linear_extrude(tube_full_height - q) | |
tube_outer_outline_2d(); | |
// The stub in the middle for supporting the screw. | |
stub(); | |
} | |
union() | |
{ | |
// The holes for the binder clip arms. | |
tube_clip_holes(); | |
// The height of the hole for the nut. | |
translate([0, 0, -nut_recess_depth]) | |
linear_extrude(nut_recess_depth * 2) | |
nut_recess_2d(); | |
// The inner part of the magnet tubes. | |
translate([0, 0, floor_thickness_inside_tubes]) | |
linear_extrude(tube_full_height) | |
tube_inner_outline_2d(); | |
} | |
} | |
module stub() | |
{ | |
// The stub in the middle is an odd shape; it is made in steps that | |
// involve differences of differences. It works approximately thus: | |
// | |
// 1. A chamfered cylinder is created. | |
// 2. A chamfered box is created. | |
// 3. #1 and #2 are intersected. | |
// 4. A sloped object is created to represent the negative of the front | |
// slope of the stub. | |
// 5. A projecting shape (an extruded "house-shaped" pentagon) is | |
// created to represent the part of the stub to be excluded from the | |
// slope cut. | |
// 6. #5 is subtracted from #4. | |
// 7. A cylinder is created to represent the negative of the screw hole. | |
// 8. #6 and #7 are subtracted from #3. This is the final stub shape. | |
ah = stub_height_including_base - q; | |
translate([0, 0, q]) | |
difference() | |
{ | |
group() | |
{ | |
intersection() | |
{ | |
rotate_extrude(angle = 360) | |
half_chamfer_topped_rect( | |
stub_outer_diameter / 2, | |
ah, | |
stub_cylinder_chamfer_width, | |
stub_cylinder_chamfer_height); | |
translate([0, stub_outer_diameter, 0]) | |
rotate([90, 0, 0]) | |
linear_extrude(stub_outer_diameter * 2) | |
chamfer_topped_rect( | |
stub_width, | |
ah, | |
stub_box_chamfer_width, | |
stub_box_chamfer_height); | |
} | |
} | |
group() | |
{ | |
x1 = -stub_outer_diameter * 2; | |
x2 = stub_outer_diameter * 2; | |
z1 = (stub_front_slope * x1); | |
z2 = (stub_front_slope * x2); | |
ch = stub_height_including_base * 2; | |
cw = stub_width * 2; | |
difference() | |
{ | |
group() | |
{ | |
translate([ | |
-cw / 2, | |
0, | |
stub_front_z_intercept + stub_height_including_base | |
]) | |
rotate([90, 0, 90]) | |
linear_extrude(cw) | |
trimming_quad(x1, z1, x2, z2, ch); | |
} | |
group() | |
{ | |
linear_extrude(ch) | |
polygon([ | |
[stub_proj_width / 2, 0], | |
[stub_proj_width / 2, -stub_proj_length], | |
[0, -stub_proj_point], | |
[-stub_proj_width / 2, -stub_proj_length], | |
[-stub_proj_width / 2, 0] | |
]); | |
} | |
} | |
translate([0, 0, -ch / 2]) | |
cylinder(r = screw_hole_diameter / 2, h = ch * 2); | |
} | |
} | |
} | |
module tube_clip_holes() | |
{ | |
for (xs = [1, -1]) | |
{ | |
scale([xs, 1, 1]) | |
group() | |
{ | |
translate([ | |
-(tube_center_spacing / 2) + tube_outer_diameter / 2 + q, | |
tube_clip_hole_start_y, | |
tube_clip_hole_z | |
]) | |
rotate([-90, 0, 90]) | |
linear_extrude(tube_clip_hole_max_depth + q) | |
for (i = [0:tube_clip_hole_count - 1]) | |
{ | |
translate([i * tube_clip_hole_center_spacing, 0, 0]) | |
circle(tube_clip_hole_diameter / 2); | |
} | |
} | |
} | |
} | |
module tube_inner_outline_2d() | |
{ | |
for (xs = [1, -1]) | |
{ | |
scale([xs, 1, 1]) | |
translate([-tube_center_spacing / 2, tube_center_position]) | |
circle(tube_inner_diameter / 2); | |
} | |
} | |
module tube_outer_outline_2d() | |
{ | |
for (xs = [1, -1]) | |
{ | |
scale([xs, 1, 1]) | |
translate([-tube_center_spacing / 2, tube_center_position]) | |
group() | |
{ | |
circle(tube_outer_diameter / 2); | |
square(tube_outer_diameter / 2); | |
} | |
} | |
} | |
module full_base_2d() | |
{ | |
group() | |
{ | |
translate([0, base_main_front_position, 0]) | |
rotate([0, 0, 180]) | |
tab(); | |
main_base_shape_2d(); | |
} | |
} | |
module nut_recess_2d() | |
{ | |
rotate([0, 0, 90]) | |
circle(nut_recess_diameter / 2, $fn = 6); | |
} | |
module main_base_shape_2d() | |
{ | |
translate([0, tube_center_position]) | |
rotate([0, 0, 180]) | |
ghost(base_width, base_front_corner_radius, base_front_corner_radius); | |
translate([0, tube_center_position]) | |
capsule(base_width, base_back_corner_radius); | |
} | |
module tab() | |
{ | |
difference() | |
{ | |
// tab land | |
translate([0, -q, 0]) | |
ghost(tab_width, tab_length + q, tab_corner_radius); | |
// tab hole | |
translate([0, tab_hole_inset + tab_hole_diameter / 2]) | |
circle(tab_hole_diameter / 2); | |
} | |
} | |
// 2D shape similar to a line segment with round end caps. | |
// Drawn horizontally and centered. | |
module capsule(w, r) | |
{ | |
_r = abs(r); | |
_w = abs(w); | |
width_without_caps = max(0, _w - (2 * _r)); | |
for (xs = [1, -1]) | |
{ | |
scale([xs, 1, 1]) | |
translate([width_without_caps / 2, 0]) | |
circle(_r); | |
} | |
square([width_without_caps, 2 * r], center = true); | |
} | |
// 2D shape similar to a rectangle with rounded corners on the top but not the bottom. | |
// Drawn in +y centered on y-axis. | |
module ghost(w, h, r) | |
{ | |
_r = abs(r); | |
_w = abs(w); | |
_h = abs(h); | |
theta = (h < 0) ? 180 : 0; | |
ah = _h - _r; | |
cut_w = _w + 1; | |
cut_h = 2 * _r + 1; | |
rotate([0, 0, theta]) | |
difference() | |
{ | |
group() | |
{ | |
translate([0, ah]) | |
capsule(_w, _r); | |
translate([-_w / 2, 0]) | |
square([_w, ah]); | |
} | |
translate([-cut_w / 2, -cut_h]) | |
square([cut_w, cut_h]); | |
} | |
} | |
// 2D shape similar to a rectangle with the upper right corner cut off. | |
// Drawn in first quadrant. | |
module half_chamfer_topped_rect(w, h, cw, ch) | |
{ | |
polygon([ | |
[w, 0], | |
[w, h - ch], | |
[w - cw, h], | |
[0, h], | |
[0, 0] | |
]); | |
} | |
// 2D shape similar to a rectangle with the upper corners cut off. | |
// Drawn in +y centered on y axis. | |
module chamfer_topped_rect(w, h, cw, ch) | |
{ | |
polygon([ | |
[w / 2, 0], | |
[w / 2, h - ch], | |
[w / 2 - cw, h], | |
[-(w / 2 - cw), h], | |
[-(w / 2), h - ch], | |
[-w / 2, 0] | |
]); | |
} | |
// 2D parallelogram made by stretching the line segment (x1,y1)-(x2,y2) upward by h. | |
module trimming_quad(x1, y1, x2, y2, h) | |
{ | |
polygon([ | |
[x1, y1], | |
[x1, y1 + h], | |
[x2, y2 + h], | |
[x2, y2] | |
]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment