discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

3D printing and Injection Molding

JB
Jon Bondy
Fri, Sep 6, 2024 4:30 PM

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

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
TA
Todd Allen
Sat, Sep 7, 2024 12:35 AM

"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

"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 >
PK
Peter Kriens
Sat, Sep 7, 2024 1:23 PM

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

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 >> >
TA
Todd Allen
Sat, Sep 7, 2024 6:09 PM

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

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-2*clip_z*tan(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-2*mjawrail_extend+mjaw_post_d+2*slop; plate_x = cam_d*cam_x_scale*1.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_w*0.5+2*slop; sm_y = cam_d*0.5*cam_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_z*1.9,cam_z],chamfer=cam_chamfer*0.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_l*0.28, w2=mjaw_l*0.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+2*eps, d=cam_d*1.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+2*sm_y0+2*eps, 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_y*0.5-fjaw_w-closed_jaw_gap*0.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_z*0.25, chamfer2=pin_head_z*0.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_d*0.5) down(pin_z+4*slop-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 >>> >>
PK
Peter Kriens
Sat, Sep 7, 2024 10:36 PM

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)
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-2*clip_z*tan(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-2*mjawrail_extend+mjaw_post_d+2*slop; > > > plate_x = cam_d*cam_x_scale*1.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_w*0.5+2*slop; > > sm_y = cam_d*0.5*cam_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_z*1.9,cam_z],chamfer=cam_chamfer*0.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_l*0.28, w2=mjaw_l*0.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+2*eps, d=cam_d*1.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+2*sm_y0+2*eps, 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_y*0.5-fjaw_w-closed_jaw_gap*0.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_z*0.25, chamfer2=pin_head_z*0.25, anchor=TOP) > > attach(TOP, BOT) zcyl(d=pin_d, h=pin_z+eps) > >