Interesting recent related video.
https://www.youtube.com/watch?v=lVRLuCScRdE
--
This email has been checked for viruses by AVG antivirus software.
www.avg.com
"My design requires very accurate holes for connectors like USB, HDMI, etc.
They should have enough friction (~0.2mm) but not too much, the tolerances
in the connectors and the printer are very complicated to handle. I started
out tuning this in the OpenSCAD source but this does not work in IM which
has a much smaller tolerance. I recently reverted to exact measures in
the source and now use CURA to expand the polygons so they have the
required size. Are there other approach for this?"
Here's an example of snap together devices about the size of an HDMI
connector each containing two cam actuated clamping jaws that I 3d print.
In the photo are two fully assembled devices and the loose parts of a third:
[image: camlocks.jpg]
For stuff with small parts I incorporate all tolerances as model parameters
so each can be tweaked separately as needed.
On Wed, Sep 4, 2024 at 2:35 AM Peter Kriens via Discuss <
discuss@lists.openscad.org> wrote:
I am very new to 3D modeling and printing. For my project I picked
OpenSCAD because I love the programmatic approach and I need lots of
variations on the same core components. After some grueling time to learn
OpenSCAD and the (complex but very good) BOSL2 library I built a number of
prototypes and printed them on a Ultimaker S3 and tested them with focus
groups.
I am now working on productizing this and I decided it will need to be
injection molded (IM). Studying the issues it seems there are quite a few
of them.
1. To my horror I found that STEP is the standard file in the IM
world, they genuinely hate STL files it seems. I can convert the STL files
decently through Fusion360 but this is almost sufficient to exit OpenSCAD.
Conversions are always lossy and it is kind of worrying that OpenSCAD is
this not used in the IM world.
2. 3D printing has the issue of support >45 degree overhangs, IM
requires that the mold can be easily released freely. This profoundly
influences the design. There are also the issues of plastic uses, sink
marks, warpage, etc. Curious if anybody has thoughts about this.
3. As a software developer I'd like to have a single source but the IM
people seem to just want to take the STEP file and then they do their magic
to it. This not completely insane since the mold making process is very
expensive.
4. In 3D printing chamfering with 45 degree has an advantage over
rounding, which needs support. However, rounding looks a lot better so is
required for a commercial product. Do I need to spread if (im) ... all over
my code? Or just take the cost of support?
5. My design requires very accurate holes for connectors like USB,
HDMI, etc. They should have enough friction (~0.2mm) but not too much, the
tolerances in the connectors and the printer are very complicated to
handle. I started out tuning this in the OpenSCAD source but this does not
work in IM which has a *much* smaller tolerance. I recently reverted
to exact measures in the source and now use CURA to expand the polygons so
they have the required size. Are there other approach for this?
Would be very interested to have a discussion that have a similar problem.
Peter Kriens
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Fantastic! Looks impressive. Willing to share openscad files and printer
settings?
Thanks,
Peter
On Sat 7 Sep 2024 at 02:35, Todd Allen speedebikes@gmail.com wrote:
"My design requires very accurate holes for connectors like USB, HDMI,
etc. They should have enough friction (~0.2mm) but not too much, the
tolerances in the connectors and the printer are very complicated to
handle. I started out tuning this in the OpenSCAD source but this does not
work in IM which has a much smaller tolerance. I recently reverted to
exact measures in the source and now use CURA to expand the polygons so
they have the required size. Are there other approach for this?"
Here's an example of snap together devices about the size of an HDMI
connector each containing two cam actuated clamping jaws that I 3d print.
In the photo are two fully assembled devices and the loose parts of a third:
[image: camlocks.jpg]
For stuff with small parts I incorporate all tolerances as model
parameters so each can be tweaked separately as needed.
On Wed, Sep 4, 2024 at 2:35 AM Peter Kriens via Discuss <
discuss@lists.openscad.org> wrote:
I am very new to 3D modeling and printing. For my project I picked
OpenSCAD because I love the programmatic approach and I need lots of
variations on the same core components. After some grueling time to learn
OpenSCAD and the (complex but very good) BOSL2 library I built a number of
prototypes and printed them on a Ultimaker S3 and tested them with focus
groups.
I am now working on productizing this and I decided it will need to be
injection molded (IM). Studying the issues it seems there are quite a few
of them.
1. To my horror I found that STEP is the standard file in the IM
world, they genuinely hate STL files it seems. I can convert the STL files
decently through Fusion360 but this is almost sufficient to exit OpenSCAD.
Conversions are always lossy and it is kind of worrying that OpenSCAD is
this not used in the IM world.
2. 3D printing has the issue of support >45 degree overhangs, IM
requires that the mold can be easily released freely. This profoundly
influences the design. There are also the issues of plastic uses, sink
marks, warpage, etc. Curious if anybody has thoughts about this.
3. As a software developer I'd like to have a single source but the
IM people seem to just want to take the STEP file and then they do their
magic to it. This not completely insane since the mold making process is
very expensive.
4. In 3D printing chamfering with 45 degree has an advantage over
rounding, which needs support. However, rounding looks a lot better so is
required for a commercial product. Do I need to spread if (im) ... all over
my code? Or just take the cost of support?
5. My design requires very accurate holes for connectors like USB,
HDMI, etc. They should have enough friction (~0.2mm) but not too much, the
tolerances in the connectors and the printer are very complicated to
handle. I started out tuning this in the OpenSCAD source but this does not
work in IM which has a *much* smaller tolerance. I recently reverted
to exact measures in the source and now use CURA to expand the polygons so
they have the required size. Are there other approach for this?
Would be very interested to have a discussion that have a similar
problem.
Peter Kriens
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
The pictured print was done on a creality K1 with the stock 0.4mm brass
nozzle in PLA. There’s an additional part STRAP() printed separately in
TPU as the devices are used with a strap to make something that might be
considered a band clamp or perhaps a fancy zip tie. The pictured print was
done with the variable scale=0.8 and slop=0.08 although if you want to play
with this I’d recommend starting with scale in the range of 1.0 to 1.5 and
a slop=0.1 or maybe a bit higher if you haven’t made much effort to tune
your printing accuracy.
As for slicing parameters the small print was done with an extrusion width
of 0.42 and layer height of 0.16 and probably 2 or 3 walls, wall order
outer 1st, 5 floors & ceilings, and 15% infill though there probably was
little to no infill. No support as the two parts printed for better
strength or accuracy in orientations needing support have it incorporated
into the objects. I print those parts with a barely touching widely gapped
brim to get sufficient bed adhesion at a lower bed temp with minimal squish
and elephant’s foot compensation but those details are things everyone
needs to sort out for their own setup of printer, bed, filament, etc. I
mostly print the straps in vase mode with fuzzy skin at 0.1 to 0.2 offset
and 0.3 to 0.4 length.
Here’s the code but with the warning this is how I commonly knock out small
projects for myself not intended as something worthy of sharing so it is
largely undocumented/uncommented and lacking in parameter validation or any
polish beyond bare functionality. My apologies if there are tabs or other
issues affecting readability:
include <BOSL2/std.scad>
include <BOSL2/rounding.scad>
include <BOSL2/beziers.scad>
include <BOSL2/joiners.scad>
$fn= $preview ? 32 : 256;
eps = 0.002;
scale = 1.0;
slop = 0.08;
case_core = true;
side_mount_dovetail = true;
locked = true;
locked_cam_rot = -5;
unlocked_cam_rot = 62;
cam_rot = locked ? locked_cam_rot:unlocked_cam_rot;
closed_jaw_gap = 0.5*scale;
cam_d = 13*scale;
cam_z = 2*scale;
cam_x_scale = 0.8;
cam_pivot_d = 4.5*scale;
cam_pivot_offset = (cam_d-cam_pivot_d)*0.2;
cam_chamfer = 0.75;
pin_d = cam_pivot_d - 1.5*slop;
pin_head_d = cam_pivot_d + 2.75;
pin_head_z = 0.75*scale;
clip_z = 1.0*scale; // was 0.75
clip_id = pin_d-2clip_ztan(30);
clip_od = cam_pivot_d + 3;
mjaw_l = cam_d*0.5;
mjaw_w = mjaw_l*0.4;
fjaw_w = mjaw_l*0.5;
fjaw_l = 4*mjaw_l/3;
fjaw_dt_l = fjaw_l*0.54;
fjaw_dt_w = fjaw_w*0.66;
fjaw_dt_h = fjaw_w*0.4;
tooth_h = 0.6*scale;
fjaw_chamfer = tooth_h;
mjawrail_w1 = mjaw_l*0.40; // bottom
mjawrail_w2 = mjaw_l*0.78; // top
mjawrail_extend = 3*scale;
mjawrail_tail_bevel_chamfer = scale*0.3;
mjaw_post_d = 1.5*scale;
mjaw_post_h = cam_z-0.8;
mjaw_chamfer = tooth_h;
cam_mjawpost_track_path_d = cam_d-2mjawrail_extend+mjaw_post_d+2slop;
plate_x = cam_dcam_x_scale1.2;
plate_y = 2*(cam_d*0.5 + cam_pivot_offset + mjaw_w + fjaw_w + tooth_h +
closed_jaw_gap);
plate_z = 1.5*scale;
pin_z = 2*(cam_z+plate_z)+2*slop;
full_pin_z = pin_z + pin_head_z + clip_z + 4*slop;
plate_pivot_offset = plate_y-(cam_d*0.5-cam_pivot_offset);
plate_edge_r = 0.5*scale;
sm_x = plate_z;
sm_x_plate_notch = sm_x*0.5;
sm_x0 = plate_x*0.5-sm_x_plate_notch;
sm_y0 = fjaw_dt_w0.5+2slop;
sm_y = cam_d0.5cam_x_scale + cam_pivot_offset + mjaw_w - sm_y0;
sm_z = pin_z;
sm_dt_spacing = sm_y+sm_y0*2;
sm_dt_z = sm_z*0.85;
sm_dt_h = sm_x*1.5;
sm_dt_w = sm_y*0.7;
sm_dt_slope = 3;
sm_dt_chamfer = 0.2;
support_thickness = 1.0;
support_gap = 0.16;
//
// CAM
//
module CAM($fn=144) {
cam0 = xscale(cam_x_scale, circle(d=cam_d));
cam1 = back(cam_pivot_offset, cam0);
cam_vnf = $preview ?
linear_sweep(cam1, h=cam_z) :
offset_sweep(cam1, h=cam_z, bottom=os_teardrop(r=cam_chamfer),
top=os_teardrop(r=cam_chamfer), steps=4);
cam_tip_t = cam_d*0.16;
cam_tip0 = xscale(cam_x_scale, arc(n=16, d=cam_d-cam_tip_t, angle=30,
start=68));
cam_tip1 =
offset_stroke(cam_tip0,start="round",end="round",width=cam_tip_t,$fn=32,
anchor="origin");
cam_tip2 = back(cam_pivot_offset, cam_tip1);
cam_tip_vnf = $preview ?
linear_sweep(cam_tip2, h=2*cam_z) :
offset_sweep(cam_tip2, h=2*cam_z,
bottom=os_teardrop(r=cam_chamfer), top=os_teardrop(r=cam_chamfer), steps=5);
handle_bezier = [[-cam_d*cam_x_scale*0.1,0],
[-cam_d*cam_x_scale*0.8, -cam_d*0.1],
[-cam_d*cam_x_scale*0.7, cam_d*0.75]
];
handle_path0 = bezier_curve(handle_bezier, splinesteps=64);
handle_path1 = back(cam_pivot_offset+cam_d*0.34, handle_path0);
handle_vnf =
path_sweep(rect([cam_z1.9,cam_z],chamfer=cam_chamfer0.75,anchor=FRONT),
path3d(handle_path1), scale=[0.5,1]);
cam_mjawpost_track_path = back(cam_pivot_offset,xscale(cam_x_scale,
arc(48, d=cam_mjawpost_track_path_d, angle=95, start=5)));
cam_mjawpost_track2_x = mjaw_post_d+2*slop;
cam_mjawpost_track2_z = mjaw_post_h+0.3;
cam_mjawpost_track2_scale = 1.2;
cam_mjawpost_track2_shape = fwd(eps,
rect([cam_mjawpost_track2_x,cam_mjawpost_track2_z], anchor=FRONT));
cam_mjawpost_track2_vnf = path_sweep(cam_mjawpost_track2_shape,
path3d(cam_mjawpost_track_path), scale=[cam_mjawpost_track2_scale,1]);
cam_pivot_vnf = down(eps, cyl(d=cam_pivot_d+2*slop, h=cam_z+2*eps,
chamfer=-slop, anchor=BOT));
color("green") zrot(cam_rot) diff() {
vnf_polyhedron(cam_vnf);
vnf_polyhedron(cam_tip_vnf);
vnf_polyhedron(handle_vnf);
move(last(handle_path1)) zcyl(d=cam_z*1.2,
l=cam_z,chamfer=cam_chamfer*0.75,anchor=BOT);
// tag("remove") vnf_polyhedron(cam_mjawpost_track_vnf);
tag("remove") vnf_polyhedron(cam_pivot_vnf);
tag("remove") union() {
vnf_polyhedron(cam_mjawpost_track2_vnf);
down(eps) move(cam_mjawpost_track_path[0])
zcyl(d=cam_mjawpost_track2_x, l=cam_mjawpost_track2_z, anchor=BOT);
down(eps) move(last(cam_mjawpost_track_path))
zcyl(d=cam_mjawpost_track2_x*cam_mjawpost_track2_scale,
l=cam_mjawpost_track2_z, anchor=BOT);
}
}
}
//
// MOVEABLE JAW
//
mjaw_offset_locked = cam_d*0.5+cam_pivot_offset+0.1;
mjaw_offset_unlocked = mjaw_offset_locked-0.1 - cam_pivot_offset*1.15;
mjaw_offset = locked ? mjaw_offset_locked : mjaw_offset_unlocked;
tooth = trapezoid(w1=mjaw_l0.28, w2=mjaw_l0.08, h=tooth_h, anchor=FRONT);
module MJAW() {
mjaw0 = rect([mjaw_l, mjaw_w], chamfer=[0,0,mjaw_chamfer,mjaw_chamfer],
anchor=FRONT);
tooth1 = back(mjaw_w, tooth);
mjaw1 = union(mjaw0, xcopies(mjaw_l*0.35, n=3, p=tooth1));
mjaw_vnf = $preview ?
linear_sweep(mjaw1, h=2*cam_z-slop, anchor=FRONT+BOT) :
offset_sweep(mjaw1, h=2*cam_z-slop, anchor=FRONT+BOT,
bottom=os_chamfer(height=0.2,angle=45),
top=os_chamfer(height=0.2,angle=45), steps=2);
mjawrail = trapezoid(w1=mjawrail_w1, w2=mjawrail_w2, h=plate_z,
chamfer=[0,0,slop,slop], anchor=BACK);
mjawrail_path = [[0,-mjawrail_extend,eps], [0,mjaw_w,eps]];
mjawrail_vnf = path_sweep(mjawrail, mjawrail_path);
back(mjaw_offset) color("orange") union() {
vnf_polyhedron(mjaw_vnf);
difference() {
vnf_polyhedron(mjawrail_vnf);
// bevel rail below post
fwd(mjawrail_extend+mjawrail_tail_bevel_chamfer) xrot(45)
cuboid([mjawrail_w2, plate_z, plate_z*1.5], anchor=TOP+BACK);
}
// fill in rail beneath teeth of jaw
intersection() {
down(plate_z) vnf_polyhedron(mjaw_vnf);
union() {
back(tooth_h) vnf_polyhedron(mjawrail_vnf);
cuboid([mjawrail_w2,2*(mjaw_w+tooth_h),cam_z], anchor=BOT);
}
}
// add the post
fwd(mjawrail_extend-mjaw_post_d*0.5) zcyl(d=mjaw_post_d,
h=mjaw_post_h, anchor=BOT);
}
}
module mjaw_printable() {
// orient MJAW for printing with support
top_half() down(plate_z*0.7) xrot(-45) up(plate_z)
fwd(mjaw_offset+mjaw_w+tooth_h) MJAW();
}
module MJAW_PRINT() {
union() {
mjaw_printable();
matrix_from_projection = frame_map(x=BACK, y=UP);
matrix_to_projection = matrix_inverse(matrix_from_projection);
union() {
// lengthwise support for the bolt
multmatrix(matrix_from_projection) linear_extrude(height =
support_thickness, center=true)
difference() {
rect([2*mjaw_w*1.5, cam_z*1.1], anchor=FRONT);
offset(r=support_gap) projection(cut=true)
multmatrix(matrix_to_projection)
mjaw_printable();
}
}
}
}
function get_plate_vnf(x, y, z) =
let(
plate = rect([x, y], rounding=2*scale),
plate_vnf = $preview ?
linear_sweep(plate, h=z, anchor=TOP) :
offset_sweep(plate, h=z, bottom=os_teardrop(r=plate_edge_r),
steps=5, anchor=TOP)
) plate_vnf;
module side_mount() {
sm_rnd = sm_x*0.25;
sm = rect([sm_x, sm_y], rounding=[sm_rnd,0,0,sm_rnd]);
sm_vnf = $preview ?
linear_sweep(sm, h=sm_z, anchor=BOT+LEFT+FRONT) :
offset_sweep(sm, h=sm_z, top=os_teardrop(r=plate_edge_r),
bottom=os_teardrop(r=plate_edge_r), steps=5, anchor=BOT+LEFT+FRONT);
if (side_mount_dovetail) union() {
vnf_polyhedron(sm_vnf);
back(sm_y*0.5) up(sm_z*0.5) right(sm_x-eps) yrot(90) zrot(90)
xrot(60, cp=[0,-sm_dt_z*0.5,0]) bottom_half() xrot(-60,
cp=[0,-sm_dt_z*0.5,0]) // trim dove tail front at 60 which will be oriented
to bottom for unsupported printing
dovetail("male", slide=sm_dt_z, width=sm_dt_w,
height=sm_dt_h, slope=sm_dt_slope, chamfer=sm_dt_chamfer);
} else vnf_polyhedron(sm_vnf);
}
module side_mount_dt_stack(n=2, bot_thick=plate_z) {
echo(bot_thick=bot_thick);
back_thick = plate_z;
slide_thick = n>1 ? (full_pin_z+slop)*n : sm_dt_z+2*slop;
up(sm_dt_h+bot_thick) fwd(back_thick*0.5) difference() {
fwd(slide_thick*0.5) cuboid([sm_dt_spacing+sm_dt_w*2,
slide_thick+back_thick, sm_dt_h+bot_thick], chamfer=plate_edge_r,
anchor=TOP+FRONT);
xcopies(sm_dt_spacing, 2) dovetail("female", slide=slide_thick,
width=sm_dt_w, height=sm_dt_h, slope=sm_dt_slope, chamfer=sm_dt_chamfer,
$slop=slop);
}
}
module CaseCore() {
color("brown") down(eps) diff(remove="x") {
cuboid([plate_x, cam_d*cam_x_scale + 2*(cam_pivot_offset + mjaw_w),
cam_z], anchor=BOT);
tag("x") down(eps) {
zcyl(h=cam_z+2*eps, r=cam_d*0.5-cam_pivot_offset+slop,
anchor=BOT);
for(r=concat(lerpn(locked_cam_rot,unlocked_cam_rot,3),lerpn(180-unlocked_cam_rot,180-(locked_cam_rot+unlocked_cam_rot)*0.75,3)))
zrot(r) back(cam_pivot_offset) xscale(cam_x_scale)
zcyl(h=cam_z+2eps, d=cam_d1.03, anchor=BOT);
// clear out width of mjaw for full length, without doing this
there are thin walls at back of unlocked mjaw
cuboid([mjaw_l+2*slop, plate_y, cam_z+2*eps], anchor=BOT);
fwd(plate_y*0.5-fjaw_dt_w-slop) cuboid([fjaw_l, fjaw_w+tooth_h,
cam_z+2*eps], anchor=BOT+FRONT);
right(plate_x*0.5+eps) back(sm_y0+eps)
cuboid([sm_x_plate_notch+slop,sm_y+2sm_y0+2eps, cam_z+2*eps],
anchor=BOT+BACK+RIGHT);
// clear entire back left corner to make room for swing of cam
arm
cuboid([plate_x*0.5+eps, plate_y*0.5+eps, cam_z+2*eps],
anchor=BOT+FRONT+RIGHT);
// clear middle of right side which has thin walls
cuboid([plate_x*0.5, plate_y*0.25, cam_z+2*eps],
anchor=BOT+LEFT);
}
}
}
//
// CASE
//
module CASE() {
fjaw0 = rect([fjaw_l, fjaw_w], chamfer=[0,0,fjaw_chamfer,fjaw_chamfer],
anchor=BACK);
fjaw1 = union(fjaw0, xcopies(mjaw_l*0.35, n=4, p=tooth));
fjaw2 = zrot(180, fjaw1);
fjaw_vnf = back(plate_y*0.5, linear_sweep(fjaw2, h=2*cam_z,
anchor=BOT+BACK));
plate_vnf = get_plate_vnf(plate_x, plate_y, plate_z);
pin_hole_vnf = up(eps, cyl(d=cam_pivot_d+2*slop, h=plate_z+2*eps,
chamfer=-slop, anchor=TOP));
mjawrail_mask = trapezoid(w1=mjawrail_w1+slop, w2=mjawrail_w2+slop,
h=plate_z+2*eps, anchor=BACK);
mjawrailtrack_y0 = cam_mjawpost_track_path_d*cam_x_scale*0.58 -
mjaw_post_d*0.5 - slop;
mjawrailtrack_path = [[0, mjawrailtrack_y0, eps], [0,
plate_y0.5-fjaw_w-closed_jaw_gap0.5, eps]];
mjawrailtrack_vnf = path_sweep(mjawrail_mask, mjawrailtrack_path);
diff() {
// bottom plate
color("blue") vnf_polyhedron([plate_vnf, fjaw_vnf]);
if (case_core) CaseCore();
// side mount
difference() {
down(plate_z) back(sm_y0) right(sm_x0) union() side_mount();
// cut side_mount to nestle snugly with top case
plate_mask_vnf = get_plate_vnf(plate_x+2*slop, plate_y,
plate_z+slop);
up(2*cam_z) xrot(180) vnf_polyhedron(plate_mask_vnf);
}
// dovetail clips to fasten case halves together
fjaw_dt_angle = 13;
fjaw_dt_taper = 3;
fjaw_dt_chamfer = 0.1;
fwd(plate_y*0.5) dovetail("male", w=fjaw_dt_l, h=fjaw_dt_h,
thickness=fjaw_dt_w-slop, angle=fjaw_dt_angle, taper=fjaw_dt_taper,
chamfer=fjaw_dt_chamfer, orient=UP, anchor=FRONT+BOT);
tag("remove") up((2.0)*cam_z+eps) xrot(180) fwd(plate_y*0.5)
dovetail("female", w=fjaw_dt_l, h=fjaw_dt_h, thickness=fjaw_dt_w,
angle=fjaw_dt_angle, taper=fjaw_dt_taper, chamfer=fjaw_dt_chamfer,
orient=UP, anchor=FRONT+BOT, $slop=slop);
// hole for pin through center of case
tag("remove") vnf_polyhedron(pin_hole_vnf);
// track for moveable jaw
tag("remove") vnf_polyhedron(mjawrailtrack_vnf);
// add wedge for bevel at rear of moveable jaw
tag("keep") back(mjawrailtrack_y0-mjawrail_tail_bevel_chamfer)
xrot(-45) bottom_half() xrot(45)
cuboid([mjawrail_w2+2*eps,plate_z,plate_z], anchor=TOP+FRONT);
}
}
//
// PIN
//
module PIN(){
$overlap = eps;
color("yellow") down(plate_z) zcyl(d=pin_head_d, h=pin_head_z,
chamfer1=pin_head_z0.25, chamfer2=pin_head_z0.25, anchor=TOP)
attach(TOP, BOT) zcyl(d=pin_d, h=pin_z+eps)
attach(TOP, BOT) zcyl(d=clip_id, h=slop+eps)
attach(TOP, BOT) zcyl(d1=clip_id, d2=pin_d, h=clip_z+eps)
attach(TOP, BOT) zcyl(d=pin_d, h=3*slop+eps);
}
module pin_printable() {
// trim bottom
top_half() down(plate_z*0.5) xrot(-30) fwd(pin_head_d*0.5)
up(pin_head_z+plate_z)
// trim top
up(pin_z+4*slop-plate_z) fwd(pin_d*0.5) xrot(30) bottom_half()
xrot(-30) back(pin_d0.5) down(pin_z+4slop-plate_z)
PIN();
}
module PIN_PRINT() {
pin_printable();
matrix_from_projection = frame_map(x=FWD, y=UP);
matrix_to_projection = matrix_inverse(matrix_from_projection);
multmatrix(matrix_from_projection) linear_extrude(height =
support_thickness, center=true) difference() {
union() {
right((pin_head_d-pin_d)*0.6) rect([pin_d*0.8, pin_d*0.45],
anchor=FRONT+LEFT);
left(0.3) rect([pin_d*0.5, pin_z*0.83], anchor=FRONT+RIGHT);
}
offset(r=support_gap) projection(cut=true)
multmatrix(matrix_to_projection)
pin_printable();
}
}
//
// CLIP
//
module CLIP() {
difference() {
zcyl(d=clip_od, h=clip_z, chamfer1=clip_z*0.25,
chamfer2=clip_z*0.25, anchor=BOT);
down(eps) zcyl(d1=clip_id+2*slop, d2=pin_d+2*slop, h=clip_z+2*eps,
anchor=BOT);
down(eps) pie_slice(h=clip_z+2*eps, d=clip_od+100*eps, ang=75,
anchor=BOT);
}
}
// returns point list forming a spiral path
function spiral_path(r0, a0, ax, r_delta_per_360) =
let(
angles = lerpn(a0, ax, floor(abs((ax-a0)*$fn/360))),
out = [
for(a = angles)
// let(r = r0 + r_delta_per_360*(a-a0)/360)
let(r = r0 + r_delta_per_360*a/360)
polar_to_xy(r,a)
]
) out;
//
// STRAP
//
module STRAP(radius, loops) {
width = 0.95*2*cam_z;
thick = 0.15 + 0.65*scale;
gap = thick;
path = spiral_path(radius, 0, loops*360, thick+gap);
shape = rect([thick,width]);
path_sweep(shape, path);
}
module inspect_assembly() {
//left_half(x=0)
right_half()
{
CASE();
MJAW();
up(slop)
CAM();
up(2*(cam_z)+slop) xrot(180) union() {
CASE();
MJAW();
up(slop) CAM();
}
PIN();
up(pin_z-plate_z+slop) CLIP();
}
}
// PARTS FOR FULL ASSEMBLY
// Put each call in a separate file for interactive export of named parts
/*
CASE(); // 2
MJAW_PRINT(); // 2
CAM(); // 2
PIN_PRINT(); // 1
CLIP(); // 1
STRAP(100, 2); // 1
*/
On Sat, Sep 7, 2024 at 8:23 AM Peter Kriens peter.kriens@aqute.biz wrote:
Fantastic! Looks impressive. Willing to share openscad files and printer
settings?
Thanks,
Peter
On Sat 7 Sep 2024 at 02:35, Todd Allen speedebikes@gmail.com wrote:
"My design requires very accurate holes for connectors like USB, HDMI,
etc. They should have enough friction (~0.2mm) but not too much, the
tolerances in the connectors and the printer are very complicated to
handle. I started out tuning this in the OpenSCAD source but this does not
work in IM which has a much smaller tolerance. I recently reverted to
exact measures in the source and now use CURA to expand the polygons so
they have the required size. Are there other approach for this?"
Here's an example of snap together devices about the size of an HDMI
connector each containing two cam actuated clamping jaws that I 3d print.
In the photo are two fully assembled devices and the loose parts of a third:
[image: camlocks.jpg]
For stuff with small parts I incorporate all tolerances as model
parameters so each can be tweaked separately as needed.
On Wed, Sep 4, 2024 at 2:35 AM Peter Kriens via Discuss <
discuss@lists.openscad.org> wrote:
I am very new to 3D modeling and printing. For my project I picked
OpenSCAD because I love the programmatic approach and I need lots of
variations on the same core components. After some grueling time to learn
OpenSCAD and the (complex but very good) BOSL2 library I built a number of
prototypes and printed them on a Ultimaker S3 and tested them with focus
groups.
I am now working on productizing this and I decided it will need to be
injection molded (IM). Studying the issues it seems there are quite a few
of them.
1. To my horror I found that STEP is the standard file in the IM
world, they genuinely hate STL files it seems. I can convert the STL files
decently through Fusion360 but this is almost sufficient to exit OpenSCAD.
Conversions are always lossy and it is kind of worrying that OpenSCAD is
this not used in the IM world.
2. 3D printing has the issue of support >45 degree overhangs, IM
requires that the mold can be easily released freely. This profoundly
influences the design. There are also the issues of plastic uses, sink
marks, warpage, etc. Curious if anybody has thoughts about this.
3. As a software developer I'd like to have a single source but the
IM people seem to just want to take the STEP file and then they do their
magic to it. This not completely insane since the mold making process is
very expensive.
4. In 3D printing chamfering with 45 degree has an advantage over
rounding, which needs support. However, rounding looks a lot better so is
required for a commercial product. Do I need to spread if (im) ... all over
my code? Or just take the cost of support?
5. My design requires very accurate holes for connectors like USB,
HDMI, etc. They should have enough friction (~0.2mm) but not too much, the
tolerances in the connectors and the printer are very complicated to
handle. I started out tuning this in the OpenSCAD source but this does not
work in IM which has a *much* smaller tolerance. I recently reverted
to exact measures in the source and now use CURA to expand the polygons so
they have the required size. Are there other approach for this?
Would be very interested to have a discussion that have a similar
problem.
Peter Kriens
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Very cool! Thanks!
On Sat 7 Sep 2024 at 20:10, Todd Allen speedebikes@gmail.com wrote:
The pictured print was done on a creality K1 with the stock 0.4mm brass
nozzle in PLA. There’s an additional part STRAP() printed separately in
TPU as the devices are used with a strap to make something that might be
considered a band clamp or perhaps a fancy zip tie. The pictured print was
done with the variable scale=0.8 and slop=0.08 although if you want to play
with this I’d recommend starting with scale in the range of 1.0 to 1.5 and
a slop=0.1 or maybe a bit higher if you haven’t made much effort to tune
your printing accuracy.
As for slicing parameters the small print was done with an extrusion width
of 0.42 and layer height of 0.16 and probably 2 or 3 walls, wall order
outer 1st, 5 floors & ceilings, and 15% infill though there probably was
little to no infill. No support as the two parts printed for better
strength or accuracy in orientations needing support have it incorporated
into the objects. I print those parts with a barely touching widely gapped
brim to get sufficient bed adhesion at a lower bed temp with minimal squish
and elephant’s foot compensation but those details are things everyone
needs to sort out for their own setup of printer, bed, filament, etc. I
mostly print the straps in vase mode with fuzzy skin at 0.1 to 0.2 offset
and 0.3 to 0.4 length.
Here’s the code but with the warning this is how I commonly knock out
small projects for myself not intended as something worthy of sharing so it
is largely undocumented/uncommented and lacking in parameter validation or
any polish beyond bare functionality. My apologies if there are tabs or
other issues affecting readability:
include <BOSL2/std.scad>
include <BOSL2/rounding.scad>
include <BOSL2/beziers.scad>
include <BOSL2/joiners.scad>
$fn= $preview ? 32 : 256;
eps = 0.002;
scale = 1.0;
slop = 0.08;
case_core = true;
side_mount_dovetail = true;
locked = true;
locked_cam_rot = -5;
unlocked_cam_rot = 62;
cam_rot = locked ? locked_cam_rot:unlocked_cam_rot;
closed_jaw_gap = 0.5*scale;
cam_d = 13*scale;
cam_z = 2*scale;
cam_x_scale = 0.8;
cam_pivot_d = 4.5*scale;
cam_pivot_offset = (cam_d-cam_pivot_d)*0.2;
cam_chamfer = 0.75;
pin_d = cam_pivot_d - 1.5*slop;
pin_head_d = cam_pivot_d + 2.75;
pin_head_z = 0.75*scale;
clip_z = 1.0*scale; // was 0.75
clip_id = pin_d-2clip_ztan(30);
clip_od = cam_pivot_d + 3;
mjaw_l = cam_d*0.5;
mjaw_w = mjaw_l*0.4;
fjaw_w = mjaw_l*0.5;
fjaw_l = 4*mjaw_l/3;
fjaw_dt_l = fjaw_l*0.54;
fjaw_dt_w = fjaw_w*0.66;
fjaw_dt_h = fjaw_w*0.4;
tooth_h = 0.6*scale;
fjaw_chamfer = tooth_h;
mjawrail_w1 = mjaw_l*0.40; // bottom
mjawrail_w2 = mjaw_l*0.78; // top
mjawrail_extend = 3*scale;
mjawrail_tail_bevel_chamfer = scale*0.3;
mjaw_post_d = 1.5*scale;
mjaw_post_h = cam_z-0.8;
mjaw_chamfer = tooth_h;
cam_mjawpost_track_path_d = cam_d-2mjawrail_extend+mjaw_post_d+2slop;
plate_x = cam_dcam_x_scale1.2;
plate_y = 2*(cam_d*0.5 + cam_pivot_offset + mjaw_w + fjaw_w + tooth_h +
closed_jaw_gap);
plate_z = 1.5*scale;
pin_z = 2*(cam_z+plate_z)+2*slop;
full_pin_z = pin_z + pin_head_z + clip_z + 4*slop;
plate_pivot_offset = plate_y-(cam_d*0.5-cam_pivot_offset);
plate_edge_r = 0.5*scale;
sm_x = plate_z;
sm_x_plate_notch = sm_x*0.5;
sm_x0 = plate_x*0.5-sm_x_plate_notch;
sm_y0 = fjaw_dt_w0.5+2slop;
sm_y = cam_d0.5cam_x_scale + cam_pivot_offset + mjaw_w - sm_y0;
sm_z = pin_z;
sm_dt_spacing = sm_y+sm_y0*2;
sm_dt_z = sm_z*0.85;
sm_dt_h = sm_x*1.5;
sm_dt_w = sm_y*0.7;
sm_dt_slope = 3;
sm_dt_chamfer = 0.2;
support_thickness = 1.0;
support_gap = 0.16;
//
// CAM
//
module CAM($fn=144) {
cam0 = xscale(cam_x_scale, circle(d=cam_d));
cam1 = back(cam_pivot_offset, cam0);
cam_vnf = $preview ?
linear_sweep(cam1, h=cam_z) :
offset_sweep(cam1, h=cam_z, bottom=os_teardrop(r=cam_chamfer),
top=os_teardrop(r=cam_chamfer), steps=4);
cam_tip_t = cam_d*0.16;
cam_tip0 = xscale(cam_x_scale, arc(n=16, d=cam_d-cam_tip_t, angle=30,
start=68));
cam_tip1 =
offset_stroke(cam_tip0,start="round",end="round",width=cam_tip_t,$fn=32,
anchor="origin");
cam_tip2 = back(cam_pivot_offset, cam_tip1);
cam_tip_vnf = $preview ?
linear_sweep(cam_tip2, h=2*cam_z) :
offset_sweep(cam_tip2, h=2*cam_z,
bottom=os_teardrop(r=cam_chamfer), top=os_teardrop(r=cam_chamfer), steps=5);
handle_bezier = [[-cam_d*cam_x_scale*0.1,0],
[-cam_d*cam_x_scale*0.8, -cam_d*0.1],
[-cam_d*cam_x_scale*0.7, cam_d*0.75]
];
handle_path0 = bezier_curve(handle_bezier, splinesteps=64);
handle_path1 = back(cam_pivot_offset+cam_d*0.34, handle_path0);
handle_vnf =
path_sweep(rect([cam_z1.9,cam_z],chamfer=cam_chamfer0.75,anchor=FRONT),
path3d(handle_path1), scale=[0.5,1]);
cam_mjawpost_track_path = back(cam_pivot_offset,xscale(cam_x_scale,
arc(48, d=cam_mjawpost_track_path_d, angle=95, start=5)));
cam_mjawpost_track2_x = mjaw_post_d+2*slop;
cam_mjawpost_track2_z = mjaw_post_h+0.3;
cam_mjawpost_track2_scale = 1.2;
cam_mjawpost_track2_shape = fwd(eps,
rect([cam_mjawpost_track2_x,cam_mjawpost_track2_z], anchor=FRONT));
cam_mjawpost_track2_vnf = path_sweep(cam_mjawpost_track2_shape,
path3d(cam_mjawpost_track_path), scale=[cam_mjawpost_track2_scale,1]);
cam_pivot_vnf = down(eps, cyl(d=cam_pivot_d+2*slop, h=cam_z+2*eps,
chamfer=-slop, anchor=BOT));
color("green") zrot(cam_rot) diff() {
vnf_polyhedron(cam_vnf);
vnf_polyhedron(cam_tip_vnf);
vnf_polyhedron(handle_vnf);
move(last(handle_path1)) zcyl(d=cam_z*1.2,
l=cam_z,chamfer=cam_chamfer*0.75,anchor=BOT);
// tag("remove") vnf_polyhedron(cam_mjawpost_track_vnf);
tag("remove") vnf_polyhedron(cam_pivot_vnf);
tag("remove") union() {
vnf_polyhedron(cam_mjawpost_track2_vnf);
down(eps) move(cam_mjawpost_track_path[0])
zcyl(d=cam_mjawpost_track2_x, l=cam_mjawpost_track2_z, anchor=BOT);
down(eps) move(last(cam_mjawpost_track_path))
zcyl(d=cam_mjawpost_track2_x*cam_mjawpost_track2_scale,
l=cam_mjawpost_track2_z, anchor=BOT);
}
}
}
//
// MOVEABLE JAW
//
mjaw_offset_locked = cam_d*0.5+cam_pivot_offset+0.1;
mjaw_offset_unlocked = mjaw_offset_locked-0.1 - cam_pivot_offset*1.15;
mjaw_offset = locked ? mjaw_offset_locked : mjaw_offset_unlocked;
tooth = trapezoid(w1=mjaw_l0.28, w2=mjaw_l0.08, h=tooth_h, anchor=FRONT);
module MJAW() {
mjaw0 = rect([mjaw_l, mjaw_w],
chamfer=[0,0,mjaw_chamfer,mjaw_chamfer], anchor=FRONT);
tooth1 = back(mjaw_w, tooth);
mjaw1 = union(mjaw0, xcopies(mjaw_l*0.35, n=3, p=tooth1));
mjaw_vnf = $preview ?
linear_sweep(mjaw1, h=2*cam_z-slop, anchor=FRONT+BOT) :
offset_sweep(mjaw1, h=2*cam_z-slop, anchor=FRONT+BOT,
bottom=os_chamfer(height=0.2,angle=45),
top=os_chamfer(height=0.2,angle=45), steps=2);
mjawrail = trapezoid(w1=mjawrail_w1, w2=mjawrail_w2, h=plate_z,
chamfer=[0,0,slop,slop], anchor=BACK);
mjawrail_path = [[0,-mjawrail_extend,eps], [0,mjaw_w,eps]];
mjawrail_vnf = path_sweep(mjawrail, mjawrail_path);
back(mjaw_offset) color("orange") union() {
vnf_polyhedron(mjaw_vnf);
difference() {
vnf_polyhedron(mjawrail_vnf);
// bevel rail below post
fwd(mjawrail_extend+mjawrail_tail_bevel_chamfer) xrot(45)
cuboid([mjawrail_w2, plate_z, plate_z*1.5], anchor=TOP+BACK);
}
// fill in rail beneath teeth of jaw
intersection() {
down(plate_z) vnf_polyhedron(mjaw_vnf);
union() {
back(tooth_h) vnf_polyhedron(mjawrail_vnf);
cuboid([mjawrail_w2,2*(mjaw_w+tooth_h),cam_z], anchor=BOT);
}
}
// add the post
fwd(mjawrail_extend-mjaw_post_d*0.5) zcyl(d=mjaw_post_d,
h=mjaw_post_h, anchor=BOT);
}
}
module mjaw_printable() {
// orient MJAW for printing with support
top_half() down(plate_z*0.7) xrot(-45) up(plate_z)
fwd(mjaw_offset+mjaw_w+tooth_h) MJAW();
}
module MJAW_PRINT() {
union() {
mjaw_printable();
matrix_from_projection = frame_map(x=BACK, y=UP);
matrix_to_projection = matrix_inverse(matrix_from_projection);
union() {
// lengthwise support for the bolt
multmatrix(matrix_from_projection) linear_extrude(height =
support_thickness, center=true)
difference() {
rect([2*mjaw_w*1.5, cam_z*1.1], anchor=FRONT);
offset(r=support_gap) projection(cut=true)
multmatrix(matrix_to_projection)
mjaw_printable();
}
}
}
}
function get_plate_vnf(x, y, z) =
let(
plate = rect([x, y], rounding=2*scale),
plate_vnf = $preview ?
linear_sweep(plate, h=z, anchor=TOP) :
offset_sweep(plate, h=z, bottom=os_teardrop(r=plate_edge_r),
steps=5, anchor=TOP)
) plate_vnf;
module side_mount() {
sm_rnd = sm_x*0.25;
sm = rect([sm_x, sm_y], rounding=[sm_rnd,0,0,sm_rnd]);
sm_vnf = $preview ?
linear_sweep(sm, h=sm_z, anchor=BOT+LEFT+FRONT) :
offset_sweep(sm, h=sm_z, top=os_teardrop(r=plate_edge_r),
bottom=os_teardrop(r=plate_edge_r), steps=5, anchor=BOT+LEFT+FRONT);
if (side_mount_dovetail) union() {
vnf_polyhedron(sm_vnf);
back(sm_y*0.5) up(sm_z*0.5) right(sm_x-eps) yrot(90) zrot(90)
xrot(60, cp=[0,-sm_dt_z*0.5,0]) bottom_half() xrot(-60,
cp=[0,-sm_dt_z*0.5,0]) // trim dove tail front at 60 which will be oriented
to bottom for unsupported printing
dovetail("male", slide=sm_dt_z, width=sm_dt_w,
height=sm_dt_h, slope=sm_dt_slope, chamfer=sm_dt_chamfer);
} else vnf_polyhedron(sm_vnf);
}
module side_mount_dt_stack(n=2, bot_thick=plate_z) {
echo(bot_thick=bot_thick);
back_thick = plate_z;
slide_thick = n>1 ? (full_pin_z+slop)*n : sm_dt_z+2*slop;
up(sm_dt_h+bot_thick) fwd(back_thick*0.5) difference() {
fwd(slide_thick*0.5) cuboid([sm_dt_spacing+sm_dt_w*2,
slide_thick+back_thick, sm_dt_h+bot_thick], chamfer=plate_edge_r,
anchor=TOP+FRONT);
xcopies(sm_dt_spacing, 2) dovetail("female", slide=slide_thick,
width=sm_dt_w, height=sm_dt_h, slope=sm_dt_slope, chamfer=sm_dt_chamfer,
$slop=slop);
}
}
module CaseCore() {
color("brown") down(eps) diff(remove="x") {
cuboid([plate_x, cam_d*cam_x_scale + 2*(cam_pivot_offset +
mjaw_w), cam_z], anchor=BOT);
tag("x") down(eps) {
zcyl(h=cam_z+2*eps, r=cam_d*0.5-cam_pivot_offset+slop,
anchor=BOT);
for(r=concat(lerpn(locked_cam_rot,unlocked_cam_rot,3),lerpn(180-unlocked_cam_rot,180-(locked_cam_rot+unlocked_cam_rot)*0.75,3)))
zrot(r) back(cam_pivot_offset) xscale(cam_x_scale)
zcyl(h=cam_z+2eps, d=cam_d1.03, anchor=BOT);
// clear out width of mjaw for full length, without doing this
there are thin walls at back of unlocked mjaw
cuboid([mjaw_l+2*slop, plate_y, cam_z+2*eps], anchor=BOT);
fwd(plate_y*0.5-fjaw_dt_w-slop) cuboid([fjaw_l,
fjaw_w+tooth_h, cam_z+2*eps], anchor=BOT+FRONT);
right(plate_x*0.5+eps) back(sm_y0+eps)
cuboid([sm_x_plate_notch+slop,sm_y+2sm_y0+2eps, cam_z+2*eps],
anchor=BOT+BACK+RIGHT);
// clear entire back left corner to make room for swing of cam
arm
cuboid([plate_x*0.5+eps, plate_y*0.5+eps, cam_z+2*eps],
anchor=BOT+FRONT+RIGHT);
// clear middle of right side which has thin walls
cuboid([plate_x*0.5, plate_y*0.25, cam_z+2*eps],
anchor=BOT+LEFT);
}
}
}
//
// CASE
//
module CASE() {
fjaw0 = rect([fjaw_l, fjaw_w],
chamfer=[0,0,fjaw_chamfer,fjaw_chamfer], anchor=BACK);
fjaw1 = union(fjaw0, xcopies(mjaw_l*0.35, n=4, p=tooth));
fjaw2 = zrot(180, fjaw1);
fjaw_vnf = back(plate_y*0.5, linear_sweep(fjaw2, h=2*cam_z,
anchor=BOT+BACK));
plate_vnf = get_plate_vnf(plate_x, plate_y, plate_z);
pin_hole_vnf = up(eps, cyl(d=cam_pivot_d+2*slop, h=plate_z+2*eps,
chamfer=-slop, anchor=TOP));
mjawrail_mask = trapezoid(w1=mjawrail_w1+slop, w2=mjawrail_w2+slop,
h=plate_z+2*eps, anchor=BACK);
mjawrailtrack_y0 = cam_mjawpost_track_path_d*cam_x_scale*0.58 -
mjaw_post_d*0.5 - slop;
mjawrailtrack_path = [[0, mjawrailtrack_y0, eps], [0,
plate_y0.5-fjaw_w-closed_jaw_gap0.5, eps]];
mjawrailtrack_vnf = path_sweep(mjawrail_mask, mjawrailtrack_path);
diff() {
// bottom plate
color("blue") vnf_polyhedron([plate_vnf, fjaw_vnf]);
if (case_core) CaseCore();
// side mount
difference() {
down(plate_z) back(sm_y0) right(sm_x0) union() side_mount();
// cut side_mount to nestle snugly with top case
plate_mask_vnf = get_plate_vnf(plate_x+2*slop, plate_y,
plate_z+slop);
up(2*cam_z) xrot(180) vnf_polyhedron(plate_mask_vnf);
}
// dovetail clips to fasten case halves together
fjaw_dt_angle = 13;
fjaw_dt_taper = 3;
fjaw_dt_chamfer = 0.1;
fwd(plate_y*0.5) dovetail("male", w=fjaw_dt_l, h=fjaw_dt_h,
thickness=fjaw_dt_w-slop, angle=fjaw_dt_angle, taper=fjaw_dt_taper,
chamfer=fjaw_dt_chamfer, orient=UP, anchor=FRONT+BOT);
tag("remove") up((2.0)*cam_z+eps) xrot(180) fwd(plate_y*0.5)
dovetail("female", w=fjaw_dt_l, h=fjaw_dt_h, thickness=fjaw_dt_w,
angle=fjaw_dt_angle, taper=fjaw_dt_taper, chamfer=fjaw_dt_chamfer,
orient=UP, anchor=FRONT+BOT, $slop=slop);
// hole for pin through center of case
tag("remove") vnf_polyhedron(pin_hole_vnf);
// track for moveable jaw
tag("remove") vnf_polyhedron(mjawrailtrack_vnf);
// add wedge for bevel at rear of moveable jaw
tag("keep") back(mjawrailtrack_y0-mjawrail_tail_bevel_chamfer)
xrot(-45) bottom_half() xrot(45)
cuboid([mjawrail_w2+2*eps,plate_z,plate_z], anchor=TOP+FRONT);
}
}
//
// PIN
//
module PIN(){
$overlap = eps;
color("yellow") down(plate_z) zcyl(d=pin_head_d, h=pin_head_z,
chamfer1=pin_head_z0.25, chamfer2=pin_head_z0.25, anchor=TOP)
attach(TOP, BOT) zcyl(d=pin_d, h=pin_z+eps)