initial commit of FluidSwitch prototype

Wed, 12 Sep 2018 12:48:28 +0200

author
mdd
date
Wed, 12 Sep 2018 12:48:28 +0200
changeset 0
15eac37578b7
child 1
a159ad715fe0

initial commit of FluidSwitch prototype

FluidSwitch/FluidSwitch_Radial.scad file | annotate | diff | comparison | revisions
libs/Threading/Naca4.scad file | annotate | diff | comparison | revisions
libs/Threading/Naca_sweep.scad file | annotate | diff | comparison | revisions
libs/Threading/Threading.scad file | annotate | diff | comparison | revisions
--- /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]]);
+}
+

mercurial