Browse Source

First proper version of BottleCap adapter

Thomas Buck 6 years ago
parent
commit
c1d7d28732
No account linked to committer's email address
4 changed files with 821 additions and 0 deletions
  1. 93
    0
      BottleCap/CapAdapter.scad
  2. 139
    0
      BottleCap/HoseAdapter.scad
  3. 218
    0
      BottleCap/NecksCaps.scad
  4. 371
    0
      BottleCap/threads.scad

+ 93
- 0
BottleCap/CapAdapter.scad View File

@@ -0,0 +1,93 @@
1
+// Soda bottle cap Co2 dispensing adapter
2
+// Made in July 2017 by xythobuz@xythobuz.de
3
+// Licensed under CC-BY-SA-NC
4
+
5
+// Necks & Caps for DIY projects
6
+// Xavan June 2016
7
+// https://www.thingiverse.com/thing:1654620
8
+// Minimum Radius: ~15mm
9
+// License: CC-BY
10
+include <NecksCaps.scad>;
11
+
12
+// cap-type specific
13
+diameter = 30.4;
14
+wall_height = 1.5;
15
+
16
+// Universal Hose Coupler & Funnel Maker
17
+// Mooncactus January 2013
18
+// https://www.thingiverse.com/thing:44850
19
+// License: CC-BY-SA
20
+include <HoseAdapter.scad>;
21
+
22
+channel_diameter = 4;
23
+wall_size = 4;
24
+pipe_diameter = 4;
25
+pipe_wall_size = 1.2;
26
+pipe_height = 20;
27
+
28
+hose_offset = 6.5;
29
+
30
+thread_diameter = 5;
31
+thread_pitch = 0.8;
32
+thread_height = 15;
33
+
34
+// OpenSCAD Threads
35
+// http://dkprojects.net/openscad-threads/
36
+include <threads.scad>;
37
+
38
+module cap() {
39
+    rotate([180, 0, 0])
40
+        //38mm3start (); // diameter: 42, radius: 21
41
+        28PCO1810 (); // diameter: 30.43, radius: 15.215
42
+        //28PCO1881 (); // diameter: 30.4, radius: 15.2
43
+    
44
+    cylinder(d = diameter, h = channel_diameter + (2 * wall_size));
45
+}
46
+
47
+module adapter() {
48
+    difference() {
49
+        cap();
50
+        
51
+        // gas input hole
52
+        translate([-diameter / 2 - 1, 0, (channel_diameter / 2) + wall_size])
53
+            rotate([0, 90, 0])
54
+            cylinder(d = channel_diameter, h = diameter / 2 - wall_size + 1);
55
+        
56
+        // liquid output hole
57
+        translate([wall_size, 0, (channel_diameter / 2) + wall_size])
58
+            rotate([0, 90, 0])
59
+            cylinder(d = channel_diameter, h = diameter / 2 - wall_size + 1);
60
+        
61
+        // gas input outlet
62
+        translate([-wall_size, 0, wall_size + channel_diameter - 20])
63
+            cylinder(d = channel_diameter, h = 20);
64
+        
65
+        // liquid output inlet
66
+        translate([wall_size, 0, wall_size + channel_diameter - 20])
67
+            cylinder(d = channel_diameter, h = 20);
68
+    }
69
+    
70
+    // liquit output inlet
71
+    translate([wall_size, 0, -pipe_height - wall_height])
72
+    difference() {
73
+        cylinder(d = pipe_diameter + (2 * pipe_wall_size), h = pipe_height);
74
+        
75
+        translate([0, 0, -1])
76
+            cylinder(d = pipe_diameter, h = pipe_height + 2);
77
+        
78
+        translate([0, 0, -1])
79
+            metric_thread(thread_diameter, thread_pitch, thread_height + 1, internal = true);
80
+    }
81
+    
82
+    translate([-diameter - hose_offset, 0, 6])
83
+        rotate([0, 90, 0])
84
+        tube_adapter();
85
+    
86
+    translate([diameter + hose_offset, 0, 6])
87
+        rotate([0, -90, 0])
88
+        tube_adapter();
89
+}
90
+
91
+translate([0, 0, channel_diameter + (2 * wall_size)])
92
+rotate([180, 0, 0])
93
+    adapter();

+ 139
- 0
BottleCap/HoseAdapter.scad View File

@@ -0,0 +1,139 @@
1
+// preview[view:north east, tilt:top diagonal]
2
+
3
+// Top cone base diameter. Usually equal or slightly bigger than the top diameter.
4
+cone2_max=12.0;
5
+
6
+// Top cone top diameter. Usually equal or slightly smaller than the base radius
7
+cone2_min=12.0;
8
+
9
+// Height of the top cone
10
+cone2_height=2;
11
+
12
+// Wall thickness of the top cone
13
+cone2_wall=4.0;
14
+
15
+// Top cone protuding width of barb-like outer rings to prevent the hose from slipping (zero to disable)
16
+cone2_barb_width=0;
17
+
18
+
19
+// Bottom cone base diameter (the outside of the lower cone. Usually equal or slightly smaller than the top, unless you want to make a funnel)
20
+cone1_min=6.8;
21
+
22
+// Bottom top diameter (usually equal or slightly bigger than the base radius, unless you want to make a funnel)
23
+cone1_max=8.6;
24
+
25
+// Height of the bottom cone
26
+cone1_height=18;
27
+
28
+// Wall thickness of the bottom cone
29
+cone1_wall=1.5;
30
+
31
+// Bottom cone protuding width of barb-like outer rings to prevent the hose from slipping (zero to disable)
32
+cone1_barb_width=0.8;
33
+
34
+
35
+// Junction height: how tall is the connection between the two cones. Make sure it is thick enough so as to avoid excessively thin walls and/or steep inner overhang. Twice the wall thickness is a good starting value.
36
+join_height=3;
37
+
38
+// Barb flatness ratio (advanced). Sets barb height as a factor of barb size. Eg. 1.0 means a 1:1 x/y aspect ratio (aka 45°), and 2.0 makes a flatter barb.
39
+barb_flatness_ratio=2;
40
+
41
+// Barb spacing ratio (advanced). Sets barb spacing as a factor of barb height. So 0 means adjacent barbs, and 1 give an identical flat space as the barbs themselves.
42
+barb_spacing_ratio=2;
43
+
44
+// Barb symetry ratio (advanced). Avoid overhang by using a strictly positive value (easier print). Symetrical barbs correspond to 0.5. Negative values give concave barbs, and makes sense only for the lower cone. Values higher than 0.5 lead to reversed barbing (probably useless). -0.2 to 1.2 are good values
45
+barb_skew_ratio=0.15;
46
+
47
+// This is only useful to double-check the objet shape and walls before printing
48
+check_guts=0; // [0:no,1:yes]
49
+
50
+//
51
+// universal_hose_adapter.scad
52
+//
53
+// By Jérémie FRANCOIS / MoonCactus / contact@tecrd.com
54
+//
55
+// Check the webservice on http://www.tecrd.com/page/liens/universal_hose_adapter (temporary URL)
56
+// Remixed for the Thingiverse customizer (less usable imo for now...)
57
+//
58
+
59
+
60
+
61
+// $fa=10;		// how fine the curved objets are (max angle between broken parts)
62
+tol=1*0.05;	// tolerance (mostly useful for openscad preview)
63
+
64
+function xpos(dmin, dmax, height, hpos) = ( dmin+(dmax-dmin)*hpos/height )/2;
65
+
66
+module hollow_cone(dmin, dmax, height, wall, barb_width) // TODO: spokes
67
+{
68
+	if(dmin>0 && dmax>0 && height>0)
69
+	{
70
+		// Hollow cone body
71
+		difference()
72
+		{
73
+			cylinder(r1=dmin/2, r2=dmax/2, h=height);
74
+			if(wall>0)
75
+				translate([0,0,-tol])
76
+					cylinder(r1= dmin/2-wall, r2= dmax/2-wall, h=height+2*tol);
77
+		}
78
+		// Babed-like rings
79
+		if(barb_width>0 && barb_flatness_ratio!=0)
80
+		{
81
+			for(bs=[barb_width*barb_flatness_ratio : 1 : barb_width*barb_flatness_ratio]) // this is just to simulate a "local" variable... :(
82
+			{
83
+				for(hpos=[
84
+					bs/2
85
+					: barb_width * barb_flatness_ratio * (1 + barb_spacing_ratio)
86
+					: height - bs/2]
87
+				)
88
+				{
89
+					translate([0,0,hpos])
90
+					rotate_extrude()
91
+						polygon( points=[
92
+							[xpos(dmin,dmax,height,hpos)-tol, 0],
93
+							[xpos(dmin,dmax,height,hpos + bs*(1-barb_skew_ratio)) + barb_width, bs * (1-barb_skew_ratio)],
94
+							[xpos(dmin,dmax,height,hpos + bs)-tol, bs],
95
+						] );
96
+				}
97
+			}
98
+		}
99
+	}
100
+}
101
+
102
+module tube_adapter() {
103
+	difference()
104
+	{
105
+		union()
106
+		{
107
+			//color([1,0,0])
108
+			hollow_cone(cone1_min, cone1_max, cone1_height, cone1_wall, cone1_barb_width);
109
+
110
+			//color([0,0,1])
111
+				translate([0,0,cone1_height+join_height+cone2_height])
112
+					rotate([180,0,0])
113
+						hollow_cone(cone2_min, cone2_max, cone2_height, cone2_wall, cone2_barb_width);
114
+
115
+			// intermediate section
116
+			if(join_height>0)
117
+			{
118
+				//color([0,1,0])
119
+				translate([0,0,cone1_height])
120
+				rotate_extrude()
121
+					polygon( points=[
122
+						[ cone1_max/2-cone1_wall, 0],
123
+						[ cone1_max/2, 0],
124
+						[ max(cone1_max,cone2_max)/2, join_height/2],
125
+						[ cone2_max/2, join_height],
126
+						[ cone2_max/2-cone2_wall, join_height],
127
+						[ min(cone1_max/2-cone1_wall,cone2_max/2-cone2_wall), join_height/2],
128
+					] );
129
+			}
130
+		}
131
+
132
+		if(check_guts!=0)
133
+		{
134
+			// I failed to understand how/if the customizer default view worked, so I split the part twice at opposite places... :p
135
+			scale([0.5,1,1]) rotate([0,0,45]) translate([0,0,-tol]) cube([100,100,100]);
136
+			//scale([0.5,1,1]) rotate([0,0,180+45]) translate([0,0,-tol]) cube([100,100,100]);
137
+		}
138
+	}
139
+}

+ 218
- 0
BottleCap/NecksCaps.scad View File

@@ -0,0 +1,218 @@
1
+// Necks & Caps for DIY projects
2
+// Xavan June 2016
3
+//https://www.thingiverse.com/thing:1654620
4
+
5
+
6
+//***** Bouchons / Caps *****
7
+//38mm3start ();
8
+//28PCO1810 ();
9
+//28PCO1881 ();
10
+//TestMotif ();
11
+
12
+//***** Goulots / Necks *****
13
+//N38mm3start ();
14
+//N28PCO1810 ();
15
+//N28PCO1881 ();
16
+
17
+//TestMotif (); // threadform test
18
+
19
+
20
+//***** ************   *****
21
+$fn=64;
22
+
23
+module screw (Sta,End,Pas,Ray){ // filet - thread
24
+Ste=5;//pas angulaire
25
+//Pas mm/360°
26
+//Ray rayon centre du motif
27
+//Sta angle de départ
28
+//End angle de fin   
29
+for (Rz = [Sta:Ste:End]) {//Rz rotation Z
30
+    a= Rz>Sta ? 1: 0;
31
+    b= Rz<End ? 1: 0;
32
+Ap=Pas*(Rz-Sta)/360;//Ap avancement du pas en Z
33
+Ap1=Ap+Pas*Ste/360;//Ap1 avancement du pas en Z+1
34
+hull (){
35
+rotate ([0,0,Rz])translate([Ray,0,Ap])motif (a);
36
+rotate ([0,0,Rz+Ste]) translate([Ray,0,Ap1])motif (b);
37
+}
38
+}
39
+}
40
+  
41
+
42
+module motif (a){//trapeze - threadform
43
+//$Z1 largeur base
44
+//$Z2 largeur sommet
45
+//$X1 distance base sommet  
46
+// dans le plan x-z
47
+cube([0.1,0.1,$Z1],true);
48
+translate([-a*$X1,0,0])cube([0.1,0.1,$Z2],true);
49
+} 
50
+
51
+
52
+module bouchon (Rb,Hb,Ep,Nc){//cap
53
+//Rb ray bouchon interieur
54
+//Hb haut bouchon interieur
55
+//Eb epais bouchon
56
+//Nc nb crans
57
+
58
+difference(){
59
+   
60
+translate ([0,0,(Hb+Ep)/2])cylinder(Hb+Ep, r=Rb+Ep, center=true);
61
+        translate ([0,0,(Ep)/2])
62
+        
63
+translate ([0,0,Hb/2+Ep])cylinder(Hb, r=Rb, center=true);  
64
+   
65
+    }
66
+    // crans
67
+for (Rz = [0:360/Nc:360]) {
68
+rotate ([0,0,Rz])translate ([Rb+Ep,0,Hb/2+Ep])cube([Ep/2,Ep,Hb],true);
69
+}
70
+    }
71
+ 
72
+ module goulot (Rb,Hb,Ep){//neck
73
+//Rb ray goulot exterieur
74
+//Hb haut goulot 
75
+//Eb epais goulot
76
+
77
+difference(){
78
+ union(){  
79
+hull(){//exterieur
80
+    translate ([0,0,Hb/2])cylinder(Hb, r=Rb-Ep/3, center=true);translate ([0,0,(Hb-Ep/3)/2])cylinder(Hb-Ep/3, r=Rb, center=true);
81
+} 
82
+     hull(){//base
83
+    translate ([0,0,Ep/4])cylinder(Ep/2, r=Rb+Ep, center=true);
84
+    translate ([0,0,Ep/2])cylinder(Ep, r=Rb, center=true); 
85
+       }  
86
+}     
87
+translate ([0,0,Hb/2])cylinder(Hb, r=Rb-Ep, center=true); //interieur 
88
+   
89
+    }
90
+    }    
91
+
92
+module TestMotif (){
93
+$Z1=2;//largeur base
94
+$Z2=1;//largeur sommet
95
+$X1=1;//distance base sommet (std 1.0)
96
+hull(){
97
+motif (1);
98
+}
99
+}
100
+
101
+//****************BOUCHONS-CAPS*********************
102
+module 38mm3start () {
103
+jeu=0.5;//jeu
104
+Ray=38/2+jeu;//rayon centre du motif
105
+Pas=9;//pas de vis
106
+Ep=1.5;//épaisseur bouchon
107
+Ej=0;//épaisseur joint gasket
108
+Dd=1.5+Ej+(Pas/3)/2;//distance demarrage depuis la base
109
+Df=2;//distance fin
110
+    
111
+$Z1=2;//largeur base
112
+$Z2=1;//largeur sommet
113
+$X1=1;//distance base sommet (std 1.0)
114
+
115
+translate([0,0,Ep+Dd]){
116
+screw (0,180,Pas,Ray);
117
+screw (120,300,Pas,Ray);
118
+screw (240,420,Pas,Ray);
119
+}
120
+bouchon (Ray,Dd+Pas/2+Df,Ep,32);
121
+}
122
+
123
+module 28PCO1810 () {
124
+jeu=0.5;//jeu
125
+Ray=27.43/2+jeu;//rayon centre du motif
126
+Pas=3.18;//pas de vis
127
+Ep=1;//épaisseur bouchon
128
+Ej=0;//épaisseur joint gasket
129
+Dd=1.5+Ej+Pas/2;//distance demarrage depuis la base
130
+Df=2;//distance fin
131
+    
132
+$Z1=2;//largeur base
133
+$Z2=1;//largeur sommet
134
+$X1=1.1;//distance base sommet (std 1.18)
135
+    
136
+translate([0,0,Ep+Dd]){
137
+screw (0,720,Pas,Ray);
138
+}
139
+bouchon (Ray,Dd+2*Pas+Df,Ep,48);
140
+}
141
+
142
+module 28PCO1881 () {
143
+jeu=0.5;//jeu
144
+Ray=27.40/2+jeu;//rayon centre du motif
145
+Pas=2.7;//pas de vis
146
+Ep=1;//épaisseur bouchon
147
+Ej=0;//épaisseur joint gasket
148
+Dd=1.5+Ej+Pas/2;//distance demarrage depuis la base
149
+Df=2;//distance fin
150
+    
151
+$Z1=1.8;//largeur base
152
+$Z2=0.8;//largeur sommet
153
+$X1=1.1;//distance base sommet (std 1.165)
154
+    
155
+translate([0,0,Ep+Dd]){
156
+screw (0,650,Pas,Ray);
157
+}
158
+bouchon (Ray,Dd+2*Pas+Df,Ep,48);
159
+}
160
+
161
+//******************GOULOTS-NECKS*******************
162
+
163
+module N28PCO1810  () {
164
+Ray=25.07/2;//rayon externe
165
+Pas=3.18;//pas de vis
166
+Ep=1.7;//épaisseur bouchon
167
+Dd=13;//hauteur depuis l'épaulement
168
+Df=1.7;//distance fin
169
+    
170
+$Z1=2;//largeur base
171
+$Z2=1;//largeur sommet
172
+$X1=-1;//distance base sommet (std 1.0)
173
+
174
+translate([0,0,Dd+Ep-Df-2*Pas-$Z1/2]){
175
+screw (0,720,Pas,Ray);
176
+}
177
+goulot (Ray,Dd+Ep,Ep);
178
+}
179
+
180
+module N28PCO1881  () {
181
+Ray=25.07/2;//rayon externe
182
+Pas=2.7;//pas de vis
183
+Ep=1.0;//épaisseur bouchon
184
+Dd=10;//hauteur depuis l'épaulement
185
+Df=1.7;//distance fin
186
+    
187
+$Z1=1.8;//largeur base
188
+$Z2=0.8;//largeur sommet
189
+$X1=-1.1;//distance base sommet (std 1.165)
190
+
191
+translate([0,0,Dd+Ep-Df-650*Pas/360-$Z1/2]){
192
+screw (0,650,Pas,Ray);
193
+}
194
+goulot (Ray,Dd+Ep,Ep);
195
+}
196
+
197
+module N38mm3start  () {
198
+Ray=36/2;//rayon externe
199
+Pas=9;//pas de vis
200
+Ep=1.4;//épaisseur bouchon
201
+Dd=9.2;//hauteur depuis l'épaulement
202
+Df=1.5;//distance fin
203
+    
204
+$Z1=2;//largeur base
205
+$Z2=1;//largeur sommet
206
+$X1=-1;//distance base sommet (std 1.165)
207
+
208
+translate([0,0,Dd+Ep-Df-Pas/2-$Z1/2]){
209
+screw (0,180,Pas,Ray);
210
+screw (120,300,Pas,Ray);
211
+screw (240,420,Pas,Ray);
212
+}
213
+difference(){
214
+    goulot (Ray,Dd+Ep,Ep);
215
+    //biseautage
216
+translate ([0,0,Dd])cylinder(h=2*Ep, r1=Ray-Ep, r2=Ray-Ep/1.5, center=true);
217
+}
218
+}

+ 371
- 0
BottleCap/threads.scad View File

@@ -0,0 +1,371 @@
1
+/*
2
+ * ISO-standard metric threads, following this specification:
3
+ *          http://en.wikipedia.org/wiki/ISO_metric_screw_thread
4
+ *
5
+ * Copyright 2016 Dan Kirshner - dan_kirshner@yahoo.com
6
+ * This program is free software: you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation, either version 3 of the License, or
9
+ * (at your option) any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * See <http://www.gnu.org/licenses/>.
17
+ *
18
+ * Version 2.2.  2017-01-01  Correction for angle; leadfac option.  (Thanks to
19
+ *                           Andrew Allen <a2intl@gmail.com>.)
20
+ * Version 2.1.  2016-12-04  Chamfer bottom end (low-z); leadin option.
21
+ * Version 2.0.  2016-11-05  Backwards compatibility (earlier OpenSCAD) fixes.
22
+ * Version 1.9.  2016-07-03  Option: tapered.
23
+ * Version 1.8.  2016-01-08  Option: (non-standard) angle.
24
+ * Version 1.7.  2015-11-28  Larger x-increment - for small-diameters.
25
+ * Version 1.6.  2015-09-01  Options: square threads, rectangular threads.
26
+ * Version 1.5.  2015-06-12  Options: thread_size, groove.
27
+ * Version 1.4.  2014-10-17  Use "faces" instead of "triangles" for polyhedron
28
+ * Version 1.3.  2013-12-01  Correct loop over turns -- don't have early cut-off
29
+ * Version 1.2.  2012-09-09  Use discrete polyhedra rather than linear_extrude ()
30
+ * Version 1.1.  2012-09-07  Corrected to right-hand threads!
31
+ */
32
+
33
+// Examples.
34
+//
35
+// Standard M8 x 1.
36
+// metric_thread (diameter=8, pitch=1, length=4);
37
+
38
+// Square thread.
39
+// metric_thread (diameter=8, pitch=1, length=4, square=true);
40
+
41
+// Non-standard: long pitch, same thread size.
42
+//metric_thread (diameter=8, pitch=4, length=4, thread_size=1, groove=true);
43
+
44
+// Non-standard: 20 mm diameter, long pitch, square "trough" width 3 mm,
45
+// depth 1 mm.
46
+//metric_thread (diameter=20, pitch=8, length=16, square=true, thread_size=6,
47
+//               groove=true, rectangle=0.333);
48
+
49
+// English: 1/4 x 20.
50
+//english_thread (diameter=1/4, threads_per_inch=20, length=1);
51
+
52
+// Tapered.  Example -- pipe size 3/4" -- per:
53
+// http://www.engineeringtoolbox.com/npt-national-pipe-taper-threads-d_750.html
54
+// english_thread (diameter=1.05, threads_per_inch=14, length=3/4, taper=1/16);
55
+
56
+// Thread for mounting on Rohloff hub.
57
+//difference () {
58
+//   cylinder (r=20, h=10, $fn=100);
59
+//
60
+//   metric_thread (diameter=34, pitch=1, length=10, internal=true, n_starts=6);
61
+//}
62
+
63
+
64
+// ----------------------------------------------------------------------------
65
+function segments (diameter) = min (50, ceil (diameter*6));
66
+
67
+
68
+// ----------------------------------------------------------------------------
69
+// diameter -    outside diameter of threads in mm. Default: 8.
70
+// pitch    -    thread axial "travel" per turn in mm.  Default: 1.
71
+// length   -    overall axial length of thread in mm.  Default: 1.
72
+// internal -    true = clearances for internal thread (e.g., a nut).
73
+//               false = clearances for external thread (e.g., a bolt).
74
+//               (Internal threads should be "cut out" from a solid using
75
+//               difference ()).
76
+// n_starts -    Number of thread starts (e.g., DNA, a "double helix," has
77
+//               n_starts=2).  See wikipedia Screw_thread.
78
+// thread_size - (non-standard) axial width of a single thread "V" - independent
79
+//               of pitch.  Default: same as pitch.
80
+// groove      - (non-standard) subtract inverted "V" from cylinder (rather than
81
+//               add protruding "V" to cylinder).
82
+// square      - Square threads (per
83
+//               https://en.wikipedia.org/wiki/Square_thread_form).
84
+// rectangle   - (non-standard) "Rectangular" thread - ratio depth/(axial) width
85
+//               Default: 1 (square).
86
+// angle       - (non-standard) angle (deg) of thread side from perpendicular to
87
+//               axis (default = standard = 30 degrees).
88
+// taper       - diameter change per length (National Pipe Thread/ANSI B1.20.1
89
+//               is 1" diameter per 16" length). Taper decreases from 'diameter'
90
+//               as z increases.
91
+// leadin      - 1 (default): chamfer (45 degree) at max-z end; 0: no chamfer;
92
+//               2: chamfer at both ends, 3: chamfer at z=0 end.
93
+// leadfac     - scale of leadin chamfer (default: 1.0 = 1/2 thread).
94
+module metric_thread (diameter=8, pitch=1, length=1, internal=false, n_starts=1,
95
+                      thread_size=-1, groove=false, square=false, rectangle=0,
96
+                      angle=30, taper=0, leadin=1, leadfac=1.0)
97
+{
98
+   // thread_size: size of thread "V" different than travel per turn (pitch).
99
+   // Default: same as pitch.
100
+   local_thread_size = thread_size == -1 ? pitch : thread_size;
101
+   local_rectangle = rectangle ? rectangle : 1;
102
+
103
+   n_segments = segments (diameter);
104
+   h = (square || rectangle) ? local_thread_size*local_rectangle/2 : local_thread_size / (2 * tan(angle));
105
+
106
+   h_fac1 = (square || rectangle) ? 0.90 : 0.625;
107
+
108
+   // External thread includes additional relief.
109
+   h_fac2 = (square || rectangle) ? 0.95 : 5.3/8;
110
+
111
+   tapered_diameter = diameter - length*taper;
112
+
113
+   difference () {
114
+      union () {
115
+         if (! groove) {
116
+            metric_thread_turns (diameter, pitch, length, internal, n_starts,
117
+                                 local_thread_size, groove, square, rectangle, angle,
118
+                                 taper);
119
+         }
120
+
121
+         difference () {
122
+
123
+            // Solid center, including Dmin truncation.
124
+            if (groove) {
125
+               cylinder (r1=diameter/2, r2=tapered_diameter/2,
126
+                         h=length, $fn=n_segments);
127
+            } else if (internal) {
128
+               cylinder (r1=diameter/2 - h*h_fac1, r2=tapered_diameter/2 - h*h_fac1,
129
+                         h=length, $fn=n_segments);
130
+            } else {
131
+
132
+               // External thread.
133
+               cylinder (r1=diameter/2 - h*h_fac2, r2=tapered_diameter/2 - h*h_fac2,
134
+                         h=length, $fn=n_segments);
135
+            }
136
+
137
+            if (groove) {
138
+               metric_thread_turns (diameter, pitch, length, internal, n_starts,
139
+                                    local_thread_size, groove, square, rectangle,
140
+                                    angle, taper);
141
+            }
142
+         }
143
+      }
144
+
145
+      // chamfer z=0 end if leadin is 2 or 3
146
+      if (leadin == 2 || leadin == 3) {
147
+         difference () {
148
+            cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
149
+
150
+            cylinder (r2=diameter/2, r1=diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
151
+                      $fn=n_segments);
152
+         }
153
+      }
154
+
155
+      // chamfer z-max end if leadin is 1 or 2.
156
+      if (leadin == 1 || leadin == 2) {
157
+         translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) {
158
+            difference () {
159
+               cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
160
+               cylinder (r1=tapered_diameter/2, r2=tapered_diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
161
+                         $fn=n_segments);
162
+            }
163
+         }
164
+      }
165
+   }
166
+}
167
+
168
+
169
+// ----------------------------------------------------------------------------
170
+// Input units in inches.
171
+// Note: units of measure in drawing are mm!
172
+module english_thread (diameter=0.25, threads_per_inch=20, length=1,
173
+                      internal=false, n_starts=1, thread_size=-1, groove=false,
174
+                      square=false, rectangle=0, angle=30, taper=0, leadin=1)
175
+{
176
+   // Convert to mm.
177
+   mm_diameter = diameter*25.4;
178
+   mm_pitch = (1.0/threads_per_inch)*25.4;
179
+   mm_length = length*25.4;
180
+
181
+   echo (str ("mm_diameter: ", mm_diameter));
182
+   echo (str ("mm_pitch: ", mm_pitch));
183
+   echo (str ("mm_length: ", mm_length));
184
+   metric_thread (mm_diameter, mm_pitch, mm_length, internal, n_starts,
185
+                  thread_size, groove, square, rectangle, angle, taper, leadin);
186
+}
187
+
188
+// ----------------------------------------------------------------------------
189
+module metric_thread_turns (diameter, pitch, length, internal, n_starts,
190
+                            thread_size, groove, square, rectangle, angle,
191
+                            taper)
192
+{
193
+   // Number of turns needed.
194
+   n_turns = floor (length/pitch);
195
+
196
+   intersection () {
197
+
198
+      // Start one below z = 0.  Gives an extra turn at each end.
199
+      for (i=[-1*n_starts : n_turns+1]) {
200
+         translate ([0, 0, i*pitch]) {
201
+            metric_thread_turn (diameter, pitch, internal, n_starts,
202
+                                thread_size, groove, square, rectangle, angle,
203
+                                taper, i*pitch);
204
+         }
205
+      }
206
+
207
+      // Cut to length.
208
+      translate ([0, 0, length/2]) {
209
+         cube ([diameter*3, diameter*3, length], center=true);
210
+      }
211
+   }
212
+}
213
+
214
+
215
+// ----------------------------------------------------------------------------
216
+module metric_thread_turn (diameter, pitch, internal, n_starts, thread_size,
217
+                           groove, square, rectangle, angle, taper, z)
218
+{
219
+   n_segments = segments (diameter);
220
+   fraction_circle = 1.0/n_segments;
221
+   for (i=[0 : n_segments-1]) {
222
+      rotate ([0, 0, i*360*fraction_circle]) {
223
+         translate ([0, 0, i*n_starts*pitch*fraction_circle]) {
224
+            //current_diameter = diameter - taper*(z + i*n_starts*pitch*fraction_circle);
225
+            thread_polyhedron ((diameter - taper*(z + i*n_starts*pitch*fraction_circle))/2,
226
+                               pitch, internal, n_starts, thread_size, groove,
227
+                               square, rectangle, angle);
228
+         }
229
+      }
230
+   }
231
+}
232
+
233
+
234
+// ----------------------------------------------------------------------------
235
+module thread_polyhedron (radius, pitch, internal, n_starts, thread_size,
236
+                          groove, square, rectangle, angle)
237
+{
238
+   n_segments = segments (radius*2);
239
+   fraction_circle = 1.0/n_segments;
240
+
241
+   local_rectangle = rectangle ? rectangle : 1;
242
+
243
+   h = (square || rectangle) ? thread_size*local_rectangle/2 : thread_size / (2 * tan(angle));
244
+   outer_r = radius + (internal ? h/20 : 0); // Adds internal relief.
245
+   //echo (str ("outer_r: ", outer_r));
246
+
247
+   // A little extra on square thread -- make sure overlaps cylinder.
248
+   h_fac1 = (square || rectangle) ? 1.1 : 0.875;
249
+   inner_r = radius - h*h_fac1; // Does NOT do Dmin_truncation - do later with
250
+                                // cylinder.
251
+
252
+   translate_y = groove ? outer_r + inner_r : 0;
253
+   reflect_x   = groove ? 1 : 0;
254
+
255
+   // Make these just slightly bigger (keep in proportion) so polyhedra will
256
+   // overlap.
257
+   x_incr_outer = (! groove ? outer_r : inner_r) * fraction_circle * 2 * PI * 1.02;
258
+   x_incr_inner = (! groove ? inner_r : outer_r) * fraction_circle * 2 * PI * 1.02;
259
+   z_incr = n_starts * pitch * fraction_circle * 1.005;
260
+
261
+   /*
262
+    (angles x0 and x3 inner are actually 60 deg)
263
+
264
+                          /\  (x2_inner, z2_inner) [2]
265
+                         /  \
266
+   (x3_inner, z3_inner) /    \
267
+                  [3]   \     \
268
+                        |\     \ (x2_outer, z2_outer) [6]
269
+                        | \    /
270
+                        |  \  /|
271
+             z          |[7]\/ / (x1_outer, z1_outer) [5]
272
+             |          |   | /
273
+             |   x      |   |/
274
+             |  /       |   / (x0_outer, z0_outer) [4]
275
+             | /        |  /     (behind: (x1_inner, z1_inner) [1]
276
+             |/         | /
277
+    y________|          |/
278
+   (r)                  / (x0_inner, z0_inner) [0]
279
+
280
+   */
281
+
282
+   x1_outer = outer_r * fraction_circle * 2 * PI;
283
+
284
+   z0_outer = (outer_r - inner_r) * tan(angle);
285
+   //echo (str ("z0_outer: ", z0_outer));
286
+
287
+   //polygon ([[inner_r, 0], [outer_r, z0_outer],
288
+   //        [outer_r, 0.5*pitch], [inner_r, 0.5*pitch]]);
289
+   z1_outer = z0_outer + z_incr;
290
+
291
+   // Give internal square threads some clearance in the z direction, too.
292
+   bottom = internal ? 0.235 : 0.25;
293
+   top    = internal ? 0.765 : 0.75;
294
+
295
+   translate ([0, translate_y, 0]) {
296
+      mirror ([reflect_x, 0, 0]) {
297
+
298
+         if (square || rectangle) {
299
+
300
+            // Rule for face ordering: look at polyhedron from outside: points must
301
+            // be in clockwise order.
302
+            polyhedron (
303
+               points = [
304
+                         [-x_incr_inner/2, -inner_r, bottom*thread_size],         // [0]
305
+                         [x_incr_inner/2, -inner_r, bottom*thread_size + z_incr], // [1]
306
+                         [x_incr_inner/2, -inner_r, top*thread_size + z_incr],    // [2]
307
+                         [-x_incr_inner/2, -inner_r, top*thread_size],            // [3]
308
+
309
+                         [-x_incr_outer/2, -outer_r, bottom*thread_size],         // [4]
310
+                         [x_incr_outer/2, -outer_r, bottom*thread_size + z_incr], // [5]
311
+                         [x_incr_outer/2, -outer_r, top*thread_size + z_incr],    // [6]
312
+                         [-x_incr_outer/2, -outer_r, top*thread_size]             // [7]
313
+                        ],
314
+
315
+               faces = [
316
+                         [0, 3, 7, 4],  // This-side trapezoid
317
+
318
+                         [1, 5, 6, 2],  // Back-side trapezoid
319
+
320
+                         [0, 1, 2, 3],  // Inner rectangle
321
+
322
+                         [4, 7, 6, 5],  // Outer rectangle
323
+
324
+                         // These are not planar, so do with separate triangles.
325
+                         [7, 2, 6],     // Upper rectangle, bottom
326
+                         [7, 3, 2],     // Upper rectangle, top
327
+
328
+                         [0, 5, 1],     // Lower rectangle, bottom
329
+                         [0, 4, 5]      // Lower rectangle, top
330
+                        ]
331
+            );
332
+         } else {
333
+
334
+            // Rule for face ordering: look at polyhedron from outside: points must
335
+            // be in clockwise order.
336
+            polyhedron (
337
+               points = [
338
+                         [-x_incr_inner/2, -inner_r, 0],                        // [0]
339
+                         [x_incr_inner/2, -inner_r, z_incr],                    // [1]
340
+                         [x_incr_inner/2, -inner_r, thread_size + z_incr],      // [2]
341
+                         [-x_incr_inner/2, -inner_r, thread_size],              // [3]
342
+
343
+                         [-x_incr_outer/2, -outer_r, z0_outer],                 // [4]
344
+                         [x_incr_outer/2, -outer_r, z0_outer + z_incr],         // [5]
345
+                         [x_incr_outer/2, -outer_r, thread_size - z0_outer + z_incr], // [6]
346
+                         [-x_incr_outer/2, -outer_r, thread_size - z0_outer]    // [7]
347
+                        ],
348
+
349
+               faces = [
350
+                         [0, 3, 7, 4],  // This-side trapezoid
351
+
352
+                         [1, 5, 6, 2],  // Back-side trapezoid
353
+
354
+                         [0, 1, 2, 3],  // Inner rectangle
355
+
356
+                         [4, 7, 6, 5],  // Outer rectangle
357
+
358
+                         // These are not planar, so do with separate triangles.
359
+                         [7, 2, 6],     // Upper rectangle, bottom
360
+                         [7, 3, 2],     // Upper rectangle, top
361
+
362
+                         [0, 5, 1],     // Lower rectangle, bottom
363
+                         [0, 4, 5]      // Lower rectangle, top
364
+                        ]
365
+            );
366
+         }
367
+      }
368
+   }
369
+}
370
+
371
+

Loading…
Cancel
Save