Wed, 12 Sep 2018 12:48:28 +0200
initial commit of FluidSwitch prototype
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FluidSwitch/FluidSwitch_Radial.scad Wed Sep 12 12:48:28 2018 +0200 @@ -0,0 +1,146 @@ +// fluid 1-to-N-way rotation Valve +// 1 Inlet, N Outlets + +// Variables: +oring_outer = 5.0; +oring_inner = 3.0; + +tube_dia = 2; + +hole_inner = 1.0; +axis_dia = 5; + +// for color mixer we need 3 base colors + black + white + additional 1 waste and 1 clean water and one output = 8 connectors +// cycle will be: +// 1) select color 1-5, load syringe, select output, unload syringe, repeat for each other color +// 2) select water, load syringe, select waste, unload syringe +outlets = 8; + +// just fiddle around with the following variables: +outlet_circle_dia = 13; +base_dia = 20; + +// roundness faces +fn = 10; + +// calculations: +oring_dia = (oring_outer - oring_inner) / 2; +outlet_angle = 360/outlets; +base_height = 6; +base_outer_dia = base_dia + 6; +outer_thread_height = 10; +outer_height = 15; +thread_pitch = 2; + +// START PROGRAM +use <../libs/Threading/Threading.scad> + +valve_lower(); + +//rotate([180,0,0]) translate([30,0,0]) +//valve_inlay(); + +//rotate([180,0,0]) translate([0,0,-60]) +// valve_cap(); + +// MODULES + +module valve_inlay() union() { + inlay_height = 5; + difference() { + translate([0,0,0.0001]) + cylinder(d=base_dia, h = inlay_height); + + // cut out the connector tube + rotate([90,0,0]) + translate([outlet_circle_dia/4,0,0]) + rotate_extrude(convexity=10) + translate([outlet_circle_dia/4, 0]) circle(d=oring_inner, $fn=fn); + + // cylinder(d=oring_inner, h=inlay_height / 2, $fn=fn); + // translate([outlet_circle_dia/2,0]) + // cylinder(d=oring_inner, h=inlay_height / 2, $fn=fn); + } + + // hex drive rod + translate([0,0,inlay_height]) + cylinder(d=axis_dia, h=20, $fn=6); +} + +module valve_cap() { + cap_sides = 50; + difference() { + union() { + translate([0,0,2]) + Threading(D = base_outer_dia + 6, pitch = thread_pitch, d=base_outer_dia, windings = (outer_thread_height/thread_pitch), angle = 55, full = true, step = 50, $fn=cap_sides); + + cylinder(d=base_outer_dia + 6, h=2, $fn=cap_sides); + } + + cylinder(d=axis_dia + 2, h=2 + 0.001, $fn=fn); + } +} + +module valve_lower() +difference() { + union() { + valve_base(); + valve_casing(); + // bottom + translate([0,0,-1.5]) cylinder(d=base_outer_dia, h=1.5); + } + + // cut out the OUTLET ring on the side + for(i = [1:outlets]) { + a = outlet_angle * i; + rotate([90,0,a]) { + translate([outlet_circle_dia/2 - hole_inner/2,tube_dia/2,0]) + rotate([0,90,0]) + cylinder(d=tube_dia, h=base_outer_dia, $fn=fn); + } + } + +} +// TODO: cut out the syringe hole (needs to be conical to fit) + + +module valve_casing() { + difference() { + union() { + translate([0,0,0.001]) + cylinder(d=base_outer_dia, h=outer_height - outer_thread_height); + + translate([0,0,outer_height - outer_thread_height]) + threading(pitch = thread_pitch, d=base_outer_dia, windings = (outer_thread_height/thread_pitch)-1, angle = 55, full = true, $fn=fn); + } + + cylinder(d=base_dia, h = outer_height + 0.001); + } +} + +module valve_base() difference() { + cylinder(d=base_dia, h=base_height); + + // inlet hole + cylinder(d=hole_inner, h=base_height, $fn=fn); + translate([0,0,base_height]) + oring(); + + // cut Outlet holes and oring carves + for(i = [1:outlets]) { + a = outlet_angle * i; + rotate([0,0,a]) { + translate([outlet_circle_dia/2,0,base_height]) + oring(); + translate([outlet_circle_dia/2,0]) + cylinder(d=hole_inner, h=base_height, $fn=fn); + } + } + +} + +module oring() { + rotate_extrude(convexity=10, $fn=fn) + translate([oring_inner/2 , 0, 0]) + circle(d=oring_dia, $fn=fn); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/Threading/Naca4.scad Wed Sep 12 12:48:28 2018 +0200 @@ -0,0 +1,55 @@ +// Naca4.scad - library for parametric airfoils of 4 digit NACA series +// Code: Rudolf Huttary, Berlin +// June 2015 +// commercial use prohibited + + +// general use: for more examples refer to sampler.scad +// naca = naca digits or 3el vector (default = 12 or [0, 0, .12]) +// L = chord length [mm] (default= 100) +// N = # sample points (default= 81) +// h = height [mm] (default= 1) +// open = close at the thin end? (default = true) +// two equivalent example calls + airfoil(naca = 2408, L = 60, N=1001, h = 30, open = false); +// airfoil(naca = [.2, .4, .32], L = 60, N=1001, h = 30, open = false); + +module help() +{ + echo(str("\n\nList of signatures in lib:\n=================\n", + "module airfoil(naca=2412, L = 100, N = 81, h = 1, open = false) - renders airfoil object\n", + "module airfoil(naca=[.2, .4, .12], L = 100, N = 81, h = 1, open = false) - renders airfoil object using percentage for camber, camber distance and thicknes\n", + "function airfoil_data(naca=12, L = 100, N = 81, open = false)\n", + "=================\n")); +} + +help(); +// this is the object +module airfoil(naca=12, L = 100, N = 81, h = 1, open = false) +{ + linear_extrude(height = h) + polygon(points = airfoil_data(naca, L, N, open)); +} + +// this is the main function providing the airfoil data +function airfoil_data(naca=12, L = 100, N = 81, open = false) = + let(Na = len(naca)!=3?NACA(naca):naca) + let(A = [.2969, -0.126, -.3516, .2843, open?-0.1015:-0.1036]) + [for (b=[-180:360/(N):179.99]) + let (x = (1-cos(b))/2) + let(yt = sign(b)*Na[2]/.2*(A*[sqrt(x), x, x*x, x*x*x, x*x*x*x])) + Na[0]==0?L*[x, yt]:L*camber(x, yt, Na[0], Na[1], sign(b))]; + +// helper functions +function NACA(naca) = + let (M = floor(naca/1000)) + let (P = floor((naca-M*1000)/100)) + [M/100, P/10, floor(naca-M*1000-P*100)/100]; + +function camber(x, y, M, P, upper) = + let(yc = (x<P)?M/P/P*(2*P*x-x*x): M/(1-P)/(1-P)*(1 - 2*P + 2*P*x -x*x)) + let(dy = (x<P)?2*M/P/P*(P-x):2*M/(1-P)/(1-P)*(P-x)) + let(th = atan(dy)) + [upper ? x - y*sin(th):x + y*sin(th), upper ? yc + y*cos(th):yc - y*cos(th)]; + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/Threading/Naca_sweep.scad Wed Sep 12 12:48:28 2018 +0200 @@ -0,0 +1,149 @@ +// Naca4_sweep.scad - sweep library +// Code: Rudolf Huttary, Berlin +// June 2015 +// commercial use prohibited + +use <Naca4.scad> + +//example1(); +//rotate([80, 180, 130]) +example(); + +// sweep from NACA1480 to NACA6480 (len = 230 mm, winding y,z = 80° +// sweeps generates a single polyhedron from multiple datasets +module example() +{ + N = 40; + sweep(gen_dat(N=5, dz=1,N=N)); + + // specific generator function + function gen_dat(M=10,dz=.1,N=10) = [for (i=[1:dz:M]) + let( L = length(i)) + let( af = vec3D( + airfoil_data([.1,.5,thickness(i)], L=length(i), N = N))) + T_(-L/2, 0, (i+1)*2, af)]; // translate airfoil + + function thickness(i) = .5*sin(i*i)+.1; + function length(i) = (60+sin(12*(i-3))*30); +} + +module help() +{ + echo(str("\n\nList of signatures in lib:\n=================\n", + "sweep(dat, convexity = 5, showslices = false, plaincaps = true) // dat - vec of vec2, with vec1 = airfoil_data\n", + "function vec3D(v, z=0) // expand vec2 to vec3", + "function rot(w=0, p) // rotate vec2", + "function T_(x=0, y=0, z=0, v) // translates vec of vec3\n", + "function R_(x=0, y=0, z=0, v) // rotates vec of vec3\n", + "function Rx_(x=0, v) // x-rotates vec of vec3\n", + "function Ry_(y=0, v) // y-rotates vec of vec3\n", + "function Rz_(z=0, v) // z-rotates vec of vec3\n", + "function T_(x=0, y=0, z=0, v) // translates vec of vec3\n", + "function Tx_(x=0, v) // x-translates vec of vec3\n", + "function Ry_(y=0, v) // y-translates vec of vec3\n", + "function Rz_(z=0, v) // z-translates vec of vec3\n", + "function S_(x=0, y=0, z=0, v) // scales vec of vec3\n", + "function Sx_(x=0, v) // x-translates vec of vec3\n", + "function Sy_(x=0, v) // y-translates vec of vec3\n", + "function Sz_(x=0, v) // z-translates vec of vec3\n", + "=================\n")); +} + + +// generate polyhedron from multiple airfoil_datasets +// dat - vec of vec1, with vec1 = simple polygon like airfoil_data, > 3 points per dataset expected +module sweep(dat, convexity = 5, showslices = false, plaincaps = true) +{ + n = len(dat); // # datasets + l = len(dat[0]); // points per dataset + if(l<=3) + echo("ERROR: sweep() expects more than 3 points per dataset"); + else + { + if(n==1) + polyhedron(points = dat[0], faces = [count(l-1, 0)]); + else{ + first = plaincaps?[count(l-1, 0)]: + faces_polygon(l, true); // triangulate first dataset + last = plaincaps?[count((n-1)*l,(n)*l-1)]: + faces_shift((n-2)*l, faces_polygon(l, false)); // triangulate last dataset + if (showslices) + for(i=[0:n-1]) + sweep([dat[i]]); + else + if (n<2) // this case is also used recursively for showslices + polyhedron(points = flat(), faces = last, convexity = 5); + else + { + polyhedron(points = flat(), + faces = concat(first, last, faces_sweep(l,n)), convexity = 5); + } + } + } + function count(a, b) = let(st = (a<b?1:-1))[for (i=[a:st:b]) i]; + function faces_shift(d, dat) = [for (i=[0:len(dat)-1]) dat[i] + [d, d, d]]; + function flat() = [for (i=[0:n-1], j=[0:l-1]) dat[i][j]]; +} + +function del(A, n) = [for(i=[0:len(A)-1]) if (n!=i)A[i]]; + +//// composition stuff for polyhedron + function faces_sweep(l, n=1) = let(M = n*l) + concat([[0,l,l-1]], // first face + [for (i=[0:l*(n-1)-2], j = [0,1]) + j==0? [i, i+1, (i+l)] : [i+1, (i+l+1), i+l]], + [[n*l-1, (n-1)*l-1, (n-1)*l]]) // last face + ; + + function faces_polygon(l, first = true) = let(odd = (l%2==1), d=first?0:l) + let(res = odd?concat([[d,d+1,d+l-1]], + [for (i=[1:(l-3)/2], j=[0,1])(j==0)?[d+i,d+i+1,d+l-i]:[d+i+1,d+l-i-1, d+l-i]]): + [for (i=[0:(l-4)/2], j=[0,1])(j==0)?[d+i,d+i+1,d+l-i-1]:[d+i+1,d+l-i-2, d+l-i-1]]) + first?facerev(res):res; + + function facerev(dat) = [for (i=[0:len(dat)-1]) [dat[i][0],dat[i][2],dat[i][1]]]; + + + +//// vector and vector set operation stuff /////////////////////// +//// Expand 2D vector into 3D +function vec3D(v, z=0) = [for(i = [0:len(v)-1]) + len(v[i])==2?[v[i][0], v[i][1], z]:v[i]+[0, 0, z]]; + +// Translation - 1D, 2D, 3D point vector ////////////////////////// +// vector along all axes +function T_(x=0, y=0, z=0, v) = let(x_ = (len(x)==3)?x:[x, y, z]) + [for (i=[0:len(v)-1]) T__(x_[0], x_[1], x_[2], p=v[i])]; +/// vector along one axis +function Tx_(x=0, v) = T_(x=x, v=v); +function Ty_(y=0, v) = T_(y=y, v=v); +function Tz_(z=0, v) = T_(z=z, v=v); +/// point along all axes 1D, 2D, 3D allowed +function T__(x=0, y=0, z=0, p) = len(p)==3?p+[x, y, z]:len(p)==2?p+[x, y]:p+x; + +//// Rotation - 2D, 3D point vector /////////////////////////////////// +// vector around all axes +function R_(x=0, y=0, z=0, v) = // 2D vectors allowed + let(x_ = (len(x)==3)?x:[x, y, z]) + len(v[0])==3?Rx_(x_[0], Ry_(x_[1], Rz_(x_[2], v))): + [for(i = [0:len(v)-1]) rot(x_[2], v[i])]; +// vector around one axis +function Rx_(w, A) = A*[[1, 0, 0], [0, cos(w), sin(w)], [0, -sin(w), cos(w)]]; +function Ry_(w, A) = A*[[cos(w), 0, sin(w)], [0, 1, 0], [-sin(w), 0, cos(w)]]; +function Rz_(w, A) = A*[[cos(w), sin(w), 0], [-sin(w), cos(w), 0], [0, 0, 1]]; + + +//// Scale - 2D, 3D point vector /////////////////////////////////// +// vector along all axes +function S_(x=1, y=1, z=1, v) = + [for (i=[0:len(v)-1]) S__(x,y,z, v[i])]; +// vector along one axis +function Sx_(x=0, v) = S_(x=x, v=v); +function Sy_(y=0, v) = S_(y=y, v=v); +function Sz_(z=0, v) = S_(z=z, v=v); +// single point in 2D +function S__(x=1, y=1, z=1, p) = + len(p)==3?[p[0]*x, p[1]*y, p[2]*z]:len(p)==2?[p[0]*x+p[1]*y]:[p[0]*x]; + + + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libs/Threading/Threading.scad Wed Sep 12 12:48:28 2018 +0200 @@ -0,0 +1,93 @@ +// Threading.scad - library for threadings +// Autor: Rudolf Huttary, Berlin 2016 + +use <Naca_sweep.scad> // http://www.thingiverse.com/thing:900137 + +// examples +showexample = 10; // choose your example number + +example(showexample) +{ +// #1 ACME thread + threading(pitch = 2, d=20, windings = 5, angle = 29); + +// #2 threaded rod 20° + threading(pitch = 2, d=20, windings = 30, angle = 20, full = true); + +// #3 nut for threaded rod 20° + Threading(pitch = 2, d=20, windings = 10, angle = 20, full = true); + +// #4 nut for threaded rod 20°, own diameter 25 mm, hires + Threading(D = 25, pitch = 2, d=20, windings = 10, angle = 20, full = true, step = 50, $fn=100); + +// #5 triple helix threaded rod + threading(pitch = 2, d=20, windings = 30, helices = 3, angle = 20, full = true); + +// #6 toothed rod (no pitch) + threading(helices = 0, angle = 20, full = true); + +// #7 toothed cube (no pitch) + threading(helices = 0, angle = 60, full = true, steps=4); + +// #8 M8 hex bolt + union(){ + threading(pitch = 1.25, d=8, windings=20, full=true); cylinder(d=14.6, h=4, $fn=6);} +// #9 M8 hex nut + Threading(D=14.6, pitch = 1.25, d=8, windings=5, full=true, $fn=6); +// #10 M8 four socket nut + Threading(D=16, pitch = 1.25, d=8, windings=5, full=true, $fn=4); +} + +module example(number=0) if(number) children(number-1); + +help(); +module help() +{ + helpstr = + "Thread library - Rudolf Huttary \n + D = {0=auto}; // Cyl diameter Threading() \n + d = 6; // outer diameter thread() \n + windings = 10; // number of windings \n + helices = 1; // number of threads \n + angle = 60; // open angle <76, bolts: 60°, ACME: 29°, toothed Racks: 20° \n + steps = 40; // resolution \n + help(); // show help in console + threading(pitch = 1, d = 6, windings = 10, helices = 1, angle = 60, steps=40, full = false) \n + Threading(D = 0, pitch = 1, r = 6, windings = 10, helices = 1, angle = 60, steps=40) \n + "; + echo (helpstr); +} + +//Threading(R=12, pitch = pitch, r=radius, windings= windings, angle = angle); + +module Threading(D = 0, pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40) +{ + R = D==0?d/2+2*pitch/PI:D/2; + translate([0,0,-pitch]) + difference() + { + translate([0,0,pitch]) + cylinder (r=R, h =pitch*(windings-helices)); + threading(pitch, d, windings, helices, angle, steps, true); + } +} + +module threading(pitch = 1, d = 12, windings = 10, helices = 1, angle = 60, steps=40, full = false) +{ // tricky: glue two 180° pieces together to get a proper manifold + r = d/2; + Steps = steps/2; + Pitch = pitch*helices; + if(full) cylinder(r = r-.5-pitch/PI, h=pitch*(windings+helices), $fn=steps); + sweep(gen_dat()); // half screw + rotate([0, 0, 180]) translate([0, 0, Pitch/2]) + sweep(gen_dat()); // half screw +echo(steps); + function gen_dat() = let(ang = 180, bar = R_(180, -90, 0, Ty_(-r+.5, vec3D(pitch/PI*Rack(windings, angle))))) + [for (i=[0:Steps]) Tz_(i/2/Steps*Pitch, Rz_(i*ang/Steps, bar))]; + + function Rack(w, angle) = + concat([[0, 2]], [for (i=[0:windings-1], j=[0:3]) + let(t = [ [0, 1], [2*tan(angle/2), -1], [PI/2, -1], [2*tan(angle/2)+PI/2, 1]]) + [t[j][0]+i*PI, t[j][1]]], [[w*PI, 1], [w*PI, 2]]); +} +