Rev Author Line No. Line
4429 jacho 1 /*
2 * ISO-standard metric threads, following this specification:
3 * http://en.wikipedia.org/wiki/ISO_metric_screw_thread
4 *
5 * Dan Kirshner - dan_kirshner@yahoo.com
6 *
7 * You are welcome to make free use of this software. Retention of my
8 * authorship credit would be appreciated.
9 *
10 * Version 1.8. 2016-01-08 Option: (non-standard) angle.
11 * Version 1.7. 2015-11-28 Larger x-increment - for small-diameters.
12 * Version 1.6. 2015-09-01 Options: square threads, rectangular threads.
13 * Version 1.5. 2015-06-12 Options: thread_size, groove.
14 * Version 1.4. 2014-10-17 Use "faces" instead of "triangles" for polyhedron
15 * Version 1.3. 2013-12-01 Correct loop over turns -- don't have early cut-off
16 * Version 1.2. 2012-09-09 Use discrete polyhedra rather than linear_extrude ()
17 * Version 1.1. 2012-09-07 Corrected to right-hand threads!
18 */
19  
20 // Examples.
21 //
22 // Standard M8 x 1.
23 // metric_thread (diameter=8, pitch=1, length=4);
24  
25 // Square thread.
26 // metric_thread (diameter=8, pitch=1, length=4, square=true);
27  
28 // Non-standard: long pitch, same thread size.
29 //metric_thread (diameter=8, pitch=4, length=4, thread_size=1, groove=true);
30  
31 // Non-standard: 20 mm diameter, long pitch, square "trough" width 3 mm,
32 // depth 1 mm.
33 //metric_thread (diameter=20, pitch=8, length=16, square=true, thread_size=6,
34 // groove=true, rectangle=0.333);
35  
36 // English: 1/4 x 20.
37 //english_thread (diameter=1/4, threads_per_inch=20, length=1);
38  
39 // Thread for mounting on Rohloff hub.
40 //difference () {
41 // cylinder (r=20, h=10, $fn=100);
42 //
43 // metric_thread (diameter=34, pitch=1, length=10, internal=true, n_starts=6);
44 //}
45  
46  
47 // ----------------------------------------------------------------------------
48 function segments (diameter) = min (50, ceil (diameter*6));
49  
50  
51 // ----------------------------------------------------------------------------
52 // internal - true = clearances for internal thread (e.g., a nut).
53 // false = clearances for external thread (e.g., a bolt).
54 // (Internal threads should be "cut out" from a solid using
55 // difference ()).
56 // n_starts - Number of thread starts (e.g., DNA, a "double helix," has
57 // n_starts=2). See wikipedia Screw_thread.
58 // thread_size - (non-standard) size of a single thread "V" - independent of
59 // pitch. Default: same as pitch.
60 // groove - (non-standard) subtract inverted "V" from cylinder (rather than
61 // add protruding "V" to cylinder).
62 // square - Square threads (per
63 // https://en.wikipedia.org/wiki/Square_thread_form).
64 // rectangle - (non-standard) "Rectangular" thread - ratio depth/width
65 // Default: 1 (square).
66 // angle - (non-standard) angle (deg) of thread side from perpendicular to
67 // axis (default = standard = 30 degrees).
68 module metric_thread (diameter=8, pitch=1, length=1, internal=false, n_starts=1,
69 thread_size=-1, groove=false, square=false, rectangle=0,
70 angle=30)
71 {
72 // thread_size: size of thread "V" different than travel per turn (pitch).
73 // Default: same as pitch.
74 local_thread_size = thread_size == -1 ? pitch : thread_size;
75 local_rectangle = rectangle ? rectangle : 1;
76  
77 n_segments = segments (diameter);
78 h = (square || rectangle) ? local_thread_size*local_rectangle/2 : local_thread_size * cos (angle);
79  
80 h_fac1 = (square || rectangle) ? 0.90 : 0.625;
81  
82 // External thread includes additional relief.
83 h_fac2 = (square || rectangle) ? 0.95 : 5.3/8;
84  
85 if (! groove) {
86 metric_thread_turns (diameter, pitch, length, internal, n_starts,
87 local_thread_size, groove, square, rectangle, angle);
88 }
89  
90 difference () {
91  
92 // Solid center, including Dmin truncation.
93 if (groove) {
94 cylinder (r=diameter/2, h=length, $fn=n_segments);
95 } else if (internal) {
96 cylinder (r=diameter/2 - h*h_fac1, h=length, $fn=n_segments);
97 } else {
98  
99 // External thread.
100 cylinder (r=diameter/2 - h*h_fac2, h=length, $fn=n_segments);
101 }
102  
103 if (groove) {
104 metric_thread_turns (diameter, pitch, length, internal, n_starts,
105 local_thread_size, groove, square, rectangle,
106 angle);
107 }
108 }
109 }
110  
111  
112 // ----------------------------------------------------------------------------
113 // Input units in inches.
114 // Note: units of measure in drawing are mm!
115 module english_thread (diameter=0.25, threads_per_inch=20, length=1,
116 internal=false, n_starts=1, thread_size=-1, groove=false,
117 square=false, rectangle=0)
118 {
119 // Convert to mm.
120 mm_diameter = diameter*25.4;
121 mm_pitch = (1.0/threads_per_inch)*25.4;
122 mm_length = length*25.4;
123  
124 echo (str ("mm_diameter: ", mm_diameter));
125 echo (str ("mm_pitch: ", mm_pitch));
126 echo (str ("mm_length: ", mm_length));
127 metric_thread (mm_diameter, mm_pitch, mm_length, internal, n_starts,
128 thread_size, groove, square, rectangle);
129 }
130  
131 // ----------------------------------------------------------------------------
132 module metric_thread_turns (diameter, pitch, length, internal, n_starts,
133 thread_size, groove, square, rectangle, angle)
134 {
135 // Number of turns needed.
136 n_turns = floor (length/pitch);
137  
138 intersection () {
139  
140 // Start one below z = 0. Gives an extra turn at each end.
141 for (i=[-1*n_starts : n_turns+1]) {
142 translate ([0, 0, i*pitch]) {
143 metric_thread_turn (diameter, pitch, internal, n_starts,
144 thread_size, groove, square, rectangle, angle);
145 }
146 }
147  
148 // Cut to length.
149 translate ([0, 0, length/2]) {
150 cube ([diameter*3, diameter*3, length], center=true);
151 }
152 }
153 }
154  
155  
156 // ----------------------------------------------------------------------------
157 module metric_thread_turn (diameter, pitch, internal, n_starts, thread_size,
158 groove, square, rectangle, angle)
159 {
160 n_segments = segments (diameter);
161 fraction_circle = 1.0/n_segments;
162 for (i=[0 : n_segments-1]) {
163 rotate ([0, 0, i*360*fraction_circle]) {
164 translate ([0, 0, i*n_starts*pitch*fraction_circle]) {
165 thread_polyhedron (diameter/2, pitch, internal, n_starts,
166 thread_size, groove, square, rectangle, angle);
167 }
168 }
169 }
170 }
171  
172  
173 // ----------------------------------------------------------------------------
174 // z (see diagram) as function of current radius.
175 // (Only good for first half-pitch.)
176 function z_fct (current_radius, radius, pitch, angle)
177 = 0.5* (current_radius - (radius - 0.875*pitch*cos (angle)))
178 /cos (angle);
179  
180 // ----------------------------------------------------------------------------
181 module thread_polyhedron (radius, pitch, internal, n_starts, thread_size,
182 groove, square, rectangle, angle)
183 {
184 n_segments = segments (radius*2);
185 fraction_circle = 1.0/n_segments;
186  
187 local_rectangle = rectangle ? rectangle : 1;
188  
189 h = (square || rectangle) ? thread_size*local_rectangle/2 : thread_size * cos (angle);
190 outer_r = radius + (internal ? h/20 : 0); // Adds internal relief.
191 //echo (str ("outer_r: ", outer_r));
192  
193 // A little extra on square thread -- make sure overlaps cylinder.
194 h_fac1 = (square || rectangle) ? 1.1 : 0.875;
195 inner_r = radius - h*h_fac1; // Does NOT do Dmin_truncation - do later with
196 // cylinder.
197  
198 translate_y = groove ? outer_r + inner_r : 0;
199 reflect_x = groove ? 1 : 0;
200  
201 // Make these just slightly bigger (keep in proportion) so polyhedra will
202 // overlap.
203 x_incr_outer = (! groove ? outer_r : inner_r) * fraction_circle * 2 * PI * 1.02;
204 x_incr_inner = (! groove ? inner_r : outer_r) * fraction_circle * 2 * PI * 1.02;
205 z_incr = n_starts * pitch * fraction_circle * 1.005;
206  
207 /*
208 (angles x0 and x3 inner are actually 60 deg)
209  
210 /\ (x2_inner, z2_inner) [2]
211 / \
212 (x3_inner, z3_inner) / \
213 [3] \ \
214 |\ \ (x2_outer, z2_outer) [6]
215 | \ /
216 | \ /|
217 z |[7]\/ / (x1_outer, z1_outer) [5]
218 | | | /
219 | x | |/
220 | / | / (x0_outer, z0_outer) [4]
221 | / | / (behind: (x1_inner, z1_inner) [1]
222 |/ | /
223 y________| |/
224 (r) / (x0_inner, z0_inner) [0]
225  
226 */
227  
228 x1_outer = outer_r * fraction_circle * 2 * PI;
229  
230 z0_outer = z_fct (outer_r, radius, thread_size, angle);
231 //echo (str ("z0_outer: ", z0_outer));
232  
233 //polygon ([[inner_r, 0], [outer_r, z0_outer],
234 // [outer_r, 0.5*pitch], [inner_r, 0.5*pitch]]);
235 z1_outer = z0_outer + z_incr;
236  
237 // Give internal square threads some clearance in the z direction, too.
238 bottom = internal ? 0.235 : 0.25;
239 top = internal ? 0.765 : 0.75;
240  
241 translate ([0, translate_y, 0]) {
242 mirror ([reflect_x, 0, 0]) {
243  
244 if (square || rectangle) {
245  
246 // Rule for face ordering: look at polyhedron from outside: points must
247 // be in clockwise order.
248 polyhedron (
249 points = [
250 [-x_incr_inner/2, -inner_r, bottom*thread_size], // [0]
251 [x_incr_inner/2, -inner_r, bottom*thread_size + z_incr], // [1]
252 [x_incr_inner/2, -inner_r, top*thread_size + z_incr], // [2]
253 [-x_incr_inner/2, -inner_r, top*thread_size], // [3]
254  
255 [-x_incr_outer/2, -outer_r, bottom*thread_size], // [4]
256 [x_incr_outer/2, -outer_r, bottom*thread_size + z_incr], // [5]
257 [x_incr_outer/2, -outer_r, top*thread_size + z_incr], // [6]
258 [-x_incr_outer/2, -outer_r, top*thread_size] // [7]
259 ],
260  
261 faces = [
262 [0, 3, 7, 4], // This-side trapezoid
263  
264 [1, 5, 6, 2], // Back-side trapezoid
265  
266 [0, 1, 2, 3], // Inner rectangle
267  
268 [4, 7, 6, 5], // Outer rectangle
269  
270 // These are not planar, so do with separate triangles.
271 [7, 2, 6], // Upper rectangle, bottom
272 [7, 3, 2], // Upper rectangle, top
273  
274 [0, 5, 1], // Lower rectangle, bottom
275 [0, 4, 5] // Lower rectangle, top
276 ]
277 );
278 } else {
279  
280 // Rule for face ordering: look at polyhedron from outside: points must
281 // be in clockwise order.
282 polyhedron (
283 points = [
284 [-x_incr_inner/2, -inner_r, 0], // [0]
285 [x_incr_inner/2, -inner_r, z_incr], // [1]
286 [x_incr_inner/2, -inner_r, thread_size + z_incr], // [2]
287 [-x_incr_inner/2, -inner_r, thread_size], // [3]
288  
289 [-x_incr_outer/2, -outer_r, z0_outer], // [4]
290 [x_incr_outer/2, -outer_r, z0_outer + z_incr], // [5]
291 [x_incr_outer/2, -outer_r, thread_size - z0_outer + z_incr], // [6]
292 [-x_incr_outer/2, -outer_r, thread_size - z0_outer] // [7]
293 ],
294  
295 faces = [
296 [0, 3, 7, 4], // This-side trapezoid
297  
298 [1, 5, 6, 2], // Back-side trapezoid
299  
300 [0, 1, 2, 3], // Inner rectangle
301  
302 [4, 7, 6, 5], // Outer rectangle
303  
304 // These are not planar, so do with separate triangles.
305 [7, 2, 6], // Upper rectangle, bottom
306 [7, 3, 2], // Upper rectangle, top
307  
308 [0, 5, 1], // Lower rectangle, bottom
309 [0, 4, 5] // Lower rectangle, top
310 ]
311 );
312 }
313 }
314 }
315 }
316  
317 // Thread for mounting on Rohloff hub.
318 difference () {
319 cylinder (r=20, h=5, $fn=100);
320  
321 metric_thread (diameter=34, pitch=1, length=5, internal=true, n_starts=6);
322 }
323  
324 metric_thread (diameter=33, pitch=1, length=10, internal=false, n_starts=6);