My self-made 3D-printable designs, mainly in OpenSCAD
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

threads.scad 16KB

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