summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--delta.jscad453
1 files changed, 453 insertions, 0 deletions
diff --git a/delta.jscad b/delta.jscad
new file mode 100644
index 0000000..63eea6c
--- a/dev/null
+++ b/delta.jscad
@@ -0,0 +1,453 @@
+var PRINT = {
+ layer_height: 0.2,
+ extrusion_width: 0.4,
+
+ fit_tolerance: 0.4,
+ slide_tolerance: 0.2
+};
+
+var CONFIG = {
+ hotend: {
+ h: 62.4, // full assembly height
+ groove: { d:12, h:6 }, // grove diameter and height
+ ungroove: { d:16, above:3.7, below: 3+4 }
+ },
+ effector: {
+ h: 6,
+ o: 20, // offset to the rod mounts line
+ rods_apart: 40,
+ cone: { shell: 1, angle: Math.PI/6 },
+ rodend: {
+ joint_w: 7, // thickness of the joint
+ screw_l: 20-1, // 20 with the head
+ screw_d: 3
+ },
+ hotend: { margin: 2 },
+ hinge: {
+ d: 3, w: 5, margin: 2.5,
+ h: 1+(6+3.7)/2, // elevation + grove + top
+ e: 1 // elevation
+ },
+ clamp: {
+ shell: 4.6,
+ d: 3,
+ margin: 2.5,
+ split: 0.6
+ },
+ mswitch: {
+ size: [ 19.8, 6, 10 ],
+ screw: {
+ d: 2, h: 10/2-2,
+ s: 1.3, // screw shell
+ o: [-9.5/2,9.5/2].map(function(x) {
+ return -19.8/2+x;
+ })
+ },
+ switch_x: 2.5
+ },
+ guide: {
+ width: 3, height: 5+1, length: 6
+ },
+ fanholder: {
+ r: 30,
+ screw: { d: 3, m: 2.5/*margin*/ },
+ w: 3
+ }
+ },
+ nut: { h: 2.3, w: 5.5 }
+};
+
+var U = {
+ hypotenuse: function(a,b) {
+ return Math.sqrt(Math.pow(a,2)+Math.pow(b,2));
+ },
+ peek: function(x,m) {
+ console.log(x,m);
+ return x;
+ }
+};
+
+/* {h:,w:} */
+function nut(o) {
+ var rv = CSG.cylinder({
+ start:[0,0,0],end:[0,0,o.h],
+ radius: o.w/2/Math.cos(Math.PI/6),
+ resolution: 6
+ });
+ rv.properties.axis_connector = new CSG.Connector([0,0,0],[0,0,1],[0,1,0]);
+ return rv;
+}
+
+var E3DV6 = {
+ dimensions: {
+ big_d: 22.3,
+
+ },
+ heatsink: function() {
+ var fn = 16;
+ var z=0;
+ var unite = [ {d:16,h:3.7},{d:12,h:6},{d:16,h:3} ].map(function(x) {
+ return CSG.cylinder({
+ start: [0,0,z], end: [0,0,z-=x.h],
+ radius: x.d/2, resolution: fn
+ });
+ });
+ unite.push(CSG.cylinder({
+ start:[0,0,z-=1.5], end:[0,0,z-=1],
+ radius: 16/2, resolution: fn
+ }));
+ for(var i=0;i<11;++i) unite.push(CSG.cylinder({
+ start:[0,0,z-=1.5], end:[0,0,z-=1],
+ radius: this.dimensions.big_d/2, resolution: fn
+ }));
+ unite.push(CSG.cylinder({
+ start:[0,0,z], end: [0,0,-12.7],
+ radiusStart: 10/2, radiusEnd: 8.5/2, /* pretty arbitrary */
+ resolution: fn
+ }));
+ var rv = union(unite);
+ rv = rv.subtract([CSG.cylinder({
+ start:[0,0,1], end: [0,0,z-1],
+ radius: 4.2/2, resolution: fn
+ }),CSG.cylinder({
+ start:[0,0,1], end: [0,0,-6.7/*somewhat arbitrary*/],
+ radius: 8/2, resolution: fn
+ }),CSG.cylinder({
+ start:[0,0,z-1], end: [0,0,z+14.8],
+ radius: 6/2 /*M7*/, resolution: fn
+ })]);
+ rv.properties.pushfit_connector = new CSG.Connector([0,0,0],[0,0,-1],[1,0,0]);
+ rv.properties.heatbreak_connector = new CSG.Connector([0,0,z+14.8],[0,0,-1],[1,0,0]);
+ rv.properties.grove_connector = new CSG.Connector([0,0,-3.7-3],[0,0,1],[1,0,0]);
+ return rv.setColor([0.8,0.8,0.8,0.9]);
+ }
+};
+
+var EFFECTOR = {
+ /* {sd: screw diameter, l: cone length, s: screw shell, a: angle from axis} */
+ cone: function effector_cone(o) {
+ var re = o.sd/2+o.s, rs = re+o.l*Math.tan(o.a||(Math.PI/4));
+ var rv = CSG.cylinder({
+ start: [0,0,0], end: [0,0,o.l],
+ radiusStart: rs, radiusEnd: re,
+ resolution: Math.floor(rs*2*2)
+ }).subtract(CSG.cylinder({
+ start:[0,0,-1], end:[0,0,o.l+1], radius: o.sd,
+ //resolution: Math.floor(o.sd*2*2)
+ }));
+ rv.properties.top_connector = new CSG.Connector([0,0,o.l],[0,0,-1],[1,0,0]);
+ rv.properties.bottom_connector = new CSG.Connector([0,0,0],[0,0,1],[1,0,0]);
+ var nuthole = nut(CONFIG.nut);
+ rv = rv.subtract(nuthole.connectTo(
+ nuthole.properties.axis_connector, rv.properties.bottom_connector,
+ false, 0
+ ));
+ return rv.intersect(CSG.cylinder({start:[0,0,0],end:[0,0,o.l],radius:6/*TODO:calculate*/}));
+ },
+ platform_bb: function platform_bb() {
+ var e = CONFIG.effector;
+ var r = U.hypotenuse(e.rods_apart/2,e.o+e.rodend.screw_d/2+e.cone.shell);
+ var rv = CSG.sphere({
+ center: [0,0,e.h/2], radius: r,
+ resolution: r*2*2
+ }).intersect(CSG.cube({
+ corner1: [-r,-r,0], corner2: [r,r,e.h]
+ }));
+ rv.properties.base_connector = new CSG.Connector([0,0,0],[0,0,1],[1,0,0]);
+ return rv;
+ },
+ effector: function effector_effector() {
+ var e = CONFIG.effector;
+ var conel = e.rodend.screw_l-e.rodend.joint_w;
+ var nutr = CONFIG.nut.w/2/Math.cos(Math.PI/6);
+ var cone = this.cone({sd:e.rodend.screw_d/2,l:conel,s:e.cone.shell,a:e.cone.angle});
+ var rcorner = U.hypotenuse(e.o-e.rodend.screw_d/2-e.cone.shell,e.rods_apart/2)-3.85; //XXX:config/calc
+ var ropen = E3DV6.dimensions.big_d/2+e.hotend.margin;
+ var rmount = this.rmount = (rcorner+ropen)/2;
+ var rv = [];
+ for(var a=0;a<360;a+=120) {
+ rv.push(union([-1,1].map(function(s) {
+ return cone.connectTo(cone.properties.top_connector,
+ new CSG.Connector([s*e.rods_apart/2,e.o,e.h/2],[-s,0,0],[0,0,1]),
+ false, 0);
+ })).union(CSG.cube({
+ corner1:[e.rods_apart/2-conel+.1,e.o-nutr,0],
+ corner2:[-e.rods_apart/2+conel-.1,
+ -rcorner,
+ e.h]
+ })).rotateZ(a));
+ }
+ rv.push(CSG.cylinder({
+ start:[0,0,0], end:[0,0,e.h],
+ radius: U.hypotenuse(e.o-nutr,e.rods_apart/2-conel)
+ }));
+ rv = union(rv).intersect(this.platform_bb()).subtract(CSG.cylinder({
+ start:[0,0,-1], end:[0,0,e.h+1],
+ radius: ropen, resolution: ropen*4
+ })).subtract([/*0, probe here*/120,240].map(function(x) { /* nut pockets */
+ return CSG.cube({
+ corner1:[-CONFIG.nut.w/2,0,(e.h-CONFIG.nut.h)/2],
+ corner2:[CONFIG.nut.w/2,-rcorner-1,(e.h+CONFIG.nut.h)/2]
+ }).union(CSG.cylinder({
+ start:[0,-rmount,-1], end:[0,-rmount,e.h+1],
+ radius: 3/2 // XXX:
+ })).subtract(CSG.cylinder({
+ start:[0,-rmount,(e.h+CONFIG.nut.h)/2],
+ end:[0,-rmount,(e.h+CONFIG.nut.h)/2+PRINT.layer_height*3/2],
+ radius: 3/2+.1
+ })).rotateZ(x);
+ })).subtract( CSG.cylinder({ // pulldown screw
+ start: [0,-rcorner+e.mswitch.size[1]+PRINT.extrusion_width+3/2/*XXX:conf*/,-1],
+ end: [0,-rcorner+e.mswitch.size[1]+PRINT.extrusion_width+3/2/*XXX:conf*/,e.h+1],
+ radius: 3/2+1 /*XXX: config */
+ })).subtract( CSG.cylinder({ /* switch-screw */
+ start: [e.mswitch.switch_x,-rcorner+e.mswitch.size[1]/2,-1],
+ end: [e.mswitch.switch_x,-rcorner+e.mswitch.size[1]/2,e.h+1],
+ radius: e.mswitch.screw.d/2
+ }));
+ // add hinges
+ rv.properties.hinge_connector=new CSG.Properties();
+ var hinges_apart=e.rods_apart/2-conel;
+ rv = rv.union([-1,1].map(function hinge(s) {
+ rv.properties.hinge_connector[s]=new CSG.Connector([s*hinges_apart,e.o,e.h+e.hinge.h],[s,0,0],[0,0,1]);
+ return CSG.cube({
+ corner1: [s*hinges_apart,e.o-e.hinge.margin-e.hinge.d/2,e.h],
+ corner2: [s*(hinges_apart+e.hinge.w),e.o+e.hinge.margin+e.hinge.d/2,e.h+e.hinge.h]
+ }).union(CSG.cylinder({
+ start: [s*hinges_apart,e.o,e.h+e.hinge.h],
+ end: [s*(hinges_apart+e.hinge.w),e.o,e.h+e.hinge.h],
+ radius: e.hinge.d/2+e.hinge.margin
+ })).subtract(CSG.cylinder({
+ start: [s*(hinges_apart-1),e.o,e.h+e.hinge.h],
+ end: [s*(hinges_apart+e.hinge.w+1),e.o,e.h+e.hinge.h],
+ radius: e.hinge.d/2
+ }));
+ }));
+ // add clamp guides
+ var cgrr = e.guide.width/3;
+ rv = rv.union([-1,1].map(function guide(s) {
+ return CSG.roundedCube({
+ center: [s*(e.mswitch.size[0]+PRINT.slide_tolerance+e.guide.width)/2,-rcorner+e.guide.length/2,e.h+e.guide.height/2-cgrr],
+ radius: [e.guide.width/2,e.guide.length/2,e.guide.height/2+cgrr],
+ roundradius: cgrr
+ }).intersect(CSG.cube({
+ center: [s*(e.mswitch.size[0]+PRINT.slide_tolerance+e.guide.width)/2,-rcorner+e.guide.length/2,e.h+e.guide.height/2],
+ radius: [e.guide.width/2,e.guide.length/2,e.guide.height/2+.1],
+ roundradius: cgrr
+ }));
+ }));
+ rv.properties.grove_connector = new CSG.Connector([0,0,e.h+e.hinge.e+6/2],[0,0,1],[1,0,0]);
+ rv.properties.rcorner = rcorner;
+ return rv.setColor([0.4,0.8,0.4,0.9]);
+ },
+ hinged: function effector_hinged(o) {
+ var e = CONFIG.effector;
+ var conel = e.rodend.screw_l-e.rodend.joint_w;
+ var hinges_apart = e.rods_apart/2-conel;
+ var hhr = e.o-e.hinge.d/2-e.hinge.margin; // hotend holder radius
+ var hhh = CONFIG.hotend.groove.h+CONFIG.hotend.ungroove.above;
+ var rv = CSG.cylinder({ /* hinge */
+ start: [-hinges_apart+PRINT.slide_tolerance,e.o,e.h+e.hinge.h],
+ end: [hinges_apart-PRINT.slide_tolerance,e.o,e.h+e.hinge.h],
+ radius: e.hinge.d/2+e.hinge.margin
+ }).union( /* lower hotend holder */
+ CSG.cylinder({
+ start: [0,0,e.h+e.hinge.e], end: [0,0,e.h+e.hinge.e+CONFIG.hotend.groove.h],
+ radius: hhr
+ }).subtract(CSG.cylinder({
+ start: [0,0,e.h+e.hinge.e-1], end: [0,0,e.h+e.hinge.e+CONFIG.hotend.groove.h+1],
+ radius: CONFIG.hotend.groove.d/2 +PRINT.fit_tolerance
+ }))
+ ).union( /* upper hotend holder */
+ CSG.cylinder({
+ start: [0,0,e.h+e.hinge.e+CONFIG.hotend.groove.h],
+ end: [0,0,e.h+e.hinge.e+CONFIG.hotend.groove.h+CONFIG.hotend.ungroove.above],
+ radius: hhr
+ }).subtract(CSG.cylinder({
+ start: [0,0,e.h+e.hinge.e+CONFIG.hotend.groove.h-1],
+ end: [0,0,e.h+e.hinge.e+CONFIG.hotend.groove.h+CONFIG.hotend.ungroove.above+1],
+ radius: CONFIG.hotend.ungroove.d/2 +PRINT.fit_tolerance
+ }))
+ ).union( /* connect mount with hinge */
+ CSG.cube({
+ corner1: [-hinges_apart+PRINT.slide_tolerance,CONFIG.hotend.ungroove.d/2+PRINT.fit_tolerance,e.h+e.hinge.e],
+ corner2: [hinges_apart-PRINT.slide_tolerance,e.o,e.h+e.hinge.h+e.hinge.d/2+e.hinge.margin]
+ })
+ ).subtract( /* hinge screwhole */
+ CSG.cylinder({
+ start: [-hinges_apart-1,e.o,e.h+e.hinge.h],
+ end: [hinges_apart+1,e.o,e.h+e.hinge.h],
+ radius: e.hinge.d/2
+ })
+ ).union( /* hold clamp together */
+ [-1,1].map(function(s) {
+ return CSG.roundedCube({
+ corner1: [s*(-hhr-e.clamp.margin*2-e.clamp.d),-e.clamp.shell,e.h+e.hinge.e],
+ corner2: [s*(-CONFIG.hotend.ungroove.d/2-PRINT.fit_tolerance),+e.clamp.shell,e.h+e.hinge.e+hhh],
+ roundradius: 1.5
+ });
+ })
+ ).subtract( /* screws for holding clamp */
+ [-1,1].map(function(s) {
+ var nuthole = nut(CONFIG.nut);
+ var x = s*(-hhr-e.clamp.margin-e.clamp.d/2);
+ return CSG.cylinder({
+ start: [x,-e.clamp.shell-1,e.h+e.hinge.e+hhh/2],
+ end: [x,e.clamp.shell+1,e.h+e.hinge.e+hhh/2],
+ radius: e.clamp.d/2
+ }).union(nuthole.connectTo(
+ nuthole.properties.axis_connector,
+ new CSG.Connector([x,e.clamp.shell,e.h+e.hinge.e+hhh/2],[0,-1,0],[0,0,1]),
+ false, 0
+ )).union(CSG.cylinder({
+ start: [x,-e.clamp.shell-1,e.h+e.hinge.e+hhh/2],
+ end: [x,0,e.h+e.hinge.e+hhh/2],
+ radius: e.clamp.d/2+PRINT.slide_tolerance
+ }));
+ })
+ );
+ var ms = o.microswitch;
+ var msedge = o.effector.properties.rcorner;
+ var msh = 9.5; // microswitch holes apart
+ var mshh = Math.abs(ms.properties.switch_connector.point.z-ms.properties.screw_connector[0].point.z); // microswitch holes height
+ rv = rv.union(CSG.cube({ // connect clamp with microswitch
+ corner1: [-ms.properties.microswitch.size.x/2,-msedge+.1,e.h+e.hinge.e],
+ corner2: [+ms.properties.microswitch.size.x/2,-CONFIG.hotend.ungroove.d/2-PRINT.fit_tolerance,e.h+e.hinge.e+hhh]
+ })).union([-msh/2,msh/2].map(function(x) { // shell for microswitch screws
+ return CSG.roundedCylinder({
+ start: [x,-CONFIG.hotend.ungroove.d/2-PRINT.fit_tolerance-(e.mswitch.screw.d/2+e.mswitch.screw.s),e.h+e.hinge.e+mshh],
+ end: [x,-msedge+ms.properties.microswitch.size.y,e.h+e.hinge.e+mshh],
+ radius: e.mswitch.screw.d/2+e.mswitch.screw.s
+ });
+ })).subtract(CSG.cube({ // cut off excess if any
+ corner1:[-hhr,-msedge+ms.properties.microswitch.size.y,e.h+e.hinge.e-1],
+ corner2:[hhr,-msedge-1,e.h+e.hinge.e+hhh+e.mswitch.screw.d+e.mswitch.screw.s+1]
+ })).subtract([-msh/2,msh/2].map(function(x) { return CSG.roundedCylinder({ // screwholes
+ start: [x,-CONFIG.hotend.ungroove.d/2-PRINT.fit_tolerance-(e.mswitch.screw.d/2+e.mswitch.screw.s),e.h+e.hinge.e+mshh],
+ end: [x,-msedge+ms.properties.microswitch.size.y,e.h+e.hinge.e+mshh],
+ radius: e.mswitch.screw.d/2
+ })})).subtract(CSG.cylinder({ // pulldown screw
+ start:[0,-msedge+ms.properties.microswitch.size.y+3/2/*XXX:config*/+PRINT.extrusion_width,e.h+e.hinge.e-1],
+ end:[0,-msedge+ms.properties.microswitch.size.y+3/2/*XXX:config*/+PRINT.extrusion_width,e.h+e.hinge.e+hhh+1],
+ radius: 3/2/*XXX:config*/
+ }));
+ rv.properties.microswitch_screw_connector = new CSG.Properties();
+ [-msh/2,msh/2].forEach(function(x,i) {
+ rv.properties.microswitch_screw_connector[i] = new CSG.Connector(
+ [x,-msedge,e.h+e.hinge.e+mshh],
+ [0,1,0], [0,0,-1]
+ );
+ });
+ return rv.setColor([0.3,0.8,0.3,0.9]);
+ },
+ split_hinged: function effector_split_hinged(hinged) {
+ var e = CONFIG.effector;
+ var b = hinged.getBounds();
+ var ymax = Math.max(Math.abs(b[0].y),Math.abs(b[1].y));
+ var zmax = Math.max(b[0].z,b[1].z);
+ return [-1,1].map(function(s) {
+ return hinged.intersect(CSG.cube({
+ corner1: [Math.min(b[0].x,b[1].x)-1,s*e.clamp.split/2,-zmax-1],
+ corner2: [Math.max(b[0].x,b[1].x)+1,s*(ymax+1),zmax+1]
+ }));
+ });
+ },
+ fanholder: function effector_fanholder() {
+ var fh = CONFIG.effector.fanholder;
+ var od = fh.screw.d+2*fh.screw.m;
+ return linear_extrude({height:fh.w},hull(
+ CAG.circle({center:[0,-this.rmount],radius:od/2}),
+ CAG.circle({center:[0,-fh.r+od/2+fh.w/2],radius:fh.w/2})
+ )).translate([0,0,-fh.w]).union(
+ linear_extrude({height:fh.w},hull(
+ CAG.circle({center:[fh.w/2,-this.rmount-od/2-fh.w/2],radius:fh.w/2}),
+ CAG.circle({center:[od/2,-fh.r],radius:od/2})
+ )).rotateY(90).translate([-fh.w/2,0,0])
+ ).subtract( CSG.cylinder({
+ start: [-fh.w,-fh.r,-od/2],
+ end: [fh.w,-fh.r,-od/2],
+ radius: fh.screw.d/2
+ })).subtract( CSG.cylinder({
+ start: [0,-this.rmount,1],
+ end: [0,-this.rmount,-fh.w-1],
+ radius: fh.screw.d/2
+ })).setColor([0.3,0.8,0.3,0.9]).rotateZ(-120);
+ }
+};
+
+function columns() {
+ var rv = [0,1,2].map(function(x) {
+ return union(vector_char(0,0,String.fromCharCode('A'.charCodeAt(0)+x)).segments.map(function(x) {
+ return rectangular_extrude(x,{w:2,h:1});
+ })).center().rotateX(90).translate([0,50,0]).rotateZ(x*120+120);
+ });
+ return union(rv);
+}
+
+function microswitch() {
+ var screw_connector = new CSG.Properties();
+ var rv = CSG.cube({ center:[0,0,2.5],radius: [19.8/2,6/2,10/2] }).union(
+ CSG.cube({ center: [2.5,0.5,6], radius: [2/2,3.5/2,5/2] })
+ ).union(
+ [-8,-1,8].map(function(x) {
+ return CSG.cube({ center:[x,0,0], radius: [0.6/2,3.2/2,13/2] })
+ })
+ ).subtract(
+ [-9.5/2,9.5/2].map(function(x,i) {
+ screw_connector[i] = new CSG.Connector([x,6/2,0],[0,-1,0],[0,0,1]);
+ return CSG.cylinder({
+ start: [x,-4,0], end: [x,4,0],
+ radius: 2/2
+ })
+ })
+ );
+ rv.properties.switch_connector = new CSG.Connector([2.5,0.5,6+5/2],[0,0,1],[0,-1,0]);
+ rv.properties.screw_connector = screw_connector;
+ rv.properties.microswitch = new CSG.Properties();
+ rv.properties.microswitch.size = new CSG.Vector3D(
+ 19.8,6,10
+ );
+ return rv;
+}
+
+function getParameterDefinitions() {
+ return [{
+ name: 'part',
+ type: 'choice',
+ values: ['platform', 'hinged', 'clamp', 'fanholder', 'alltogethernow'],
+ captions: ['Effector platform','Hinged part', 'Clamp', 'Fan holder', 'All together now!'],
+ caption: 'Part',
+ initial: 'alltogethernow'
+ }];
+}
+
+function main(params) {
+ var e = EFFECTOR.effector();
+ var hs = E3DV6.heatsink();
+ hs = hs.connectTo(hs.properties.grove_connector,e.properties.grove_connector,false,0);
+ var ms = microswitch();
+ var hd = EFFECTOR.hinged({
+ microswitch:ms,effector:e
+ });
+ ms = ms.connectTo(
+ ms.properties.screw_connector[0],
+ hd.properties.microswitch_screw_connector[0],
+ false, 0);
+ var hdhd = EFFECTOR.split_hinged(hd);
+ var fh = EFFECTOR.fanholder();
+ return union({
+ platform: e,
+ hinged: hdhd[1],
+ clamp: hdhd[0],
+ fanholder: fh,
+ alltogethernow: [e,hdhd[0],hdhd[1], columns(),hs,ms,fh]
+ }[params.part||'alltogethernow'])
+ var rv = union(
+ e,
+ hs,
+ columns(),
+ ///hd,
+ hdhd[0], hdhd[1],
+ ms);
+ return rv;
+}