SpHEAR_windscreen.scad 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. //
  2. // Spherical Harmonics Ear Project (*SpHEAR)
  3. //
  4. // Windscreen modules
  5. //
  6. // Copyright 2017, Fernando Lopez-Lezcano, All Rights Reserved
  7. // nando@ccrma.stanford.edu
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU General Public License as published by
  11. // the Free Software Foundation, either version 3 of the License, or
  12. // (at your option) any later version.
  13. //
  14. // This program is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. // GNU General Public License for more details.
  18. //
  19. // You should have received a copy of the GNU General Public License
  20. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. //
  22. // 3d Models released under the Creative Commons license as follows:
  23. // Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
  24. // http://creativecommons.org/licenses/by-nc-sa/4.0/
  25. include <SpHEAR_common.scad>
  26. // http://dkprojects.net/openscad-threads/
  27. // used for the windscreeen mount threads
  28. include <threads.scad>;
  29. // default number of facets for rendering
  30. facets = 128;
  31. ////
  32. //// default model parameters
  33. ////
  34. // number of helixes of windscreen frame
  35. windscreen_sides = 12;
  36. // radius of windscreen beams
  37. windscreen_beam_radius = 1.3;
  38. // radius of frame connectors
  39. windscreen_conn_radius = windscreen_beam_radius + 0.8;
  40. // height of connector pin
  41. windscreen_pin_height = 4.0;
  42. // windscreen frame
  43. module sphear_windscreen_frame(sides, height, radius, beam_radius, twist) {
  44. inc = 360/sides;
  45. for (r = [0:inc:360]) for (t = [1, -1]) rotate([0, 0, r]) {
  46. render() {
  47. linear_extrude(height = height, center = false, convexity = 0, twist = twist * t, $fn = facets/2) {
  48. translate([radius, 0, 0]) {
  49. circle(r = beam_radius, $fn = facets/2);
  50. }
  51. }
  52. }
  53. }
  54. }
  55. // windscreen inset frame
  56. module sphear_windscreen_inset_frame(sides, height, radius, iradius, beam_radius, xscale = 1.0, yscale = 1.0) {
  57. inc = 360/sides;
  58. difference() {
  59. for (r = [0:inc:360]) for (t = [1, -1]) rotate([0, 0, r]) {
  60. render() {
  61. hull() {
  62. translate([iradius, 0, 0]) {
  63. scale([xscale, yscale, 1.0]) cylinder(r = beam_radius, h = thin_mint, $fn = facets);
  64. }
  65. rotate([0, 0, inc/2 * t]) translate([radius, 0, height]) {
  66. cylinder(r = beam_radius, h = thin_mint, $fn = facets);
  67. }
  68. }
  69. }
  70. }
  71. cylinder(r = iradius, h = height, $fn = facets);
  72. }
  73. }
  74. // windscreen frame reinforcements
  75. module sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, zrotation, yrotation) {
  76. for (r = [0:360/sides:360]) rotate([0, 0, r + zrotation]) {
  77. translate([radius, 0, 0]) {
  78. render() rotate([0, yrotation, 0]) intersection() {
  79. scale([1.0, 1.55, 1.0]) {
  80. translate([0, 0, -beam_radius * 2]) {
  81. cylinder(r = beam_radius, h = beam_radius * 4, $fn = facets);
  82. }
  83. }
  84. scale([1, 2, 2.5]) sphere(r = beam_radius, $fn = facets);
  85. }
  86. }
  87. }
  88. }
  89. // windscreen dome
  90. module sphear_windscreen_dome(sides, radius, beam_radius) {
  91. arcs = sides/2 - 1;
  92. ang = 360 / sides;
  93. difference() {
  94. for (r = [0, 90]) rotate([0, 0, r]) {
  95. for (t = [1, -1]) {
  96. translate([radius * sin(ang/2) * t, 0, 0]) rotate([0, 90, 0]) {
  97. render() rotate_extrude(convexity = 10, $fn = facets) {
  98. translate([radius * cos(ang/2), 0, 0]) {
  99. circle(r = beam_radius, $fn = facets);
  100. }
  101. }
  102. }
  103. translate([radius * sin(ang/(2/3)) * t, 0, 0]) rotate([0, 90, 0]) {
  104. render() rotate_extrude(convexity = 10, $fn = facets) {
  105. translate([radius * cos(ang/(2/3)), 0, 0]) {
  106. circle(r = beam_radius, $fn = facets);
  107. }
  108. }
  109. }
  110. }
  111. }
  112. brad = radius + 2 * beam_radius + thin_mint;
  113. translate([-brad, -brad, - 2 * brad]) {
  114. cube([2 * brad, 2 * brad, 2 * brad]);
  115. }
  116. }
  117. }
  118. // octagonal windscreen mount to body with thread
  119. module sphear_windscreen_mount(height, radius, beam_radius) {
  120. octagon_radius = (radius + 2 * beam_radius + wall) * cos(PI/8);
  121. difference() {
  122. cylinder(r = radius + 2 * beam_radius + windscreen_thread_depth, h = height, $fn = facets);
  123. metric_thread(diameter = radius * 2 + windscreen_thread_fit, pitch = windscreen_thread_pitch,
  124. length = height, angle = windscreen_thread_angle, internal = true);
  125. // make outside be a octagon instead of a circle
  126. rotate([0, 0, 22.5]) translate([0, 0, -thin_mint]) {
  127. difference() {
  128. cylinder(r = 1.5 * radius, h = height + 2 * thin_mint);
  129. cylinder(r = octagon_radius, h = height + 2 * thin_mint, $fn = 8);
  130. }
  131. }
  132. }
  133. // marker for center of screen
  134. translate([-(radius + wall), 0, 0]) {
  135. cylinder(r = 1.0, h = height, $fn = facets);
  136. }
  137. }
  138. // round windscreen mount to body with thread
  139. module sphear_windscreen_round_mount(height, radius, wradius, wall) {
  140. difference() {
  141. cylinder(r = radius + wall, h = height, $fn = facets);
  142. metric_thread(diameter = radius * 2 + windscreen_thread_fit, pitch = windscreen_thread_pitch,
  143. length = height, angle = windscreen_thread_angle, internal = true);
  144. }
  145. // outer ring that attaches to windscreen
  146. difference() {
  147. union() {
  148. cylinder(r = wradius, h = height/2, $fn = facets);
  149. translate([0, 0, height/2]) {
  150. cylinder(r1 = wradius, r2 = radius + wall, h = height/2, $fn = facets);
  151. }
  152. }
  153. cylinder(r = radius + wall, h = height, $fn = facets);
  154. }
  155. // marker for center of microphone
  156. translate([-(wradius), 0, 0]) {
  157. cylinder(r = 1.0, h = height/2, $fn = facets);
  158. }
  159. }
  160. // round windscreen thread cover
  161. module sphear_windscreen_thread_cover(height, radius, wall) {
  162. difference() {
  163. cylinder(r = radius + wall, h = height, $fn = facets);
  164. metric_thread(diameter = radius * 2 + windscreen_thread_fit, pitch = windscreen_thread_pitch,
  165. length = height, angle = windscreen_thread_angle, internal = true);
  166. }
  167. // smooth transition to flare
  168. *translate([0, 0, height/2]) {
  169. difference() {
  170. translate([0, 0, height/2]) {
  171. cylinder(r2 = radius - windscreen_thread_depth/2, r1 = radius + wall, h = height/3, $fn = facets);
  172. }
  173. cylinder(r2 = radius - windscreen_thread_depth, r1 = radius, h = height, $fn = facets);
  174. }
  175. }
  176. }
  177. // upper windscreen frame
  178. module sphear_upper_windscreen(sides, height, radius, beam_radius, conn_radius, pin_height, connectors = true) {
  179. ang = 360 / sides;
  180. // dome at top
  181. translate([0, 0, height]) {
  182. sphear_windscreen_dome(sides, radius, beam_radius);
  183. }
  184. // spiral wireframe
  185. translate([0, 0, 2]) {
  186. difference() {
  187. sphear_windscreen_frame(sides, height, radius, beam_radius, 45);
  188. if (connectors) {
  189. // remove bottom of beams to make space for the connectors
  190. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  191. translate([radius, -beam_radius/2, 0]) {
  192. cylinder(r = conn_radius, h = pin_height - 1.0, $fn = facets);
  193. }
  194. }
  195. }
  196. }
  197. }
  198. if (connectors) {
  199. // connectors to lower frame
  200. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  201. translate([radius, -beam_radius/2, 0]) {
  202. difference() {
  203. union() {
  204. cylinder(r = conn_radius, h = pin_height + 1.0, $fn = facets);
  205. translate([0, 0, pin_height + 1]) {
  206. sphere(r = conn_radius, $fn = facets);
  207. }
  208. }
  209. cylinder(r = beam_radius + fit, h = pin_height + 0.5, $fn = facets);
  210. }
  211. }
  212. }
  213. // bottom ring, prevents connectors to lower frame from toppling when printing
  214. difference() {
  215. scale([1.0, 1.0, 1.5]) rotate_extrude(convexity = 10, $fn = facets/2) {
  216. translate([radius, 0, 0]) {
  217. circle(r = wall, $fn = facets/2);
  218. }
  219. }
  220. translate([0, 0, -2 * wall]) {
  221. cylinder(r = radius + wall, h = 2 * wall + thin_mint, $fn = facets/2);
  222. }
  223. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  224. translate([radius, -beam_radius/2, -2]) {
  225. cylinder(r = conn_radius - thin_mint, h = 6.0 + thin_mint, $fn = facets/2);
  226. }
  227. }
  228. }
  229. }
  230. // crossing reinforcements
  231. // first mid crossing
  232. translate([0, 0, height/3 + 2.0]) {
  233. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, ang/2, 0);
  234. }
  235. // second mid crossing
  236. translate([0, 0, height*2/3 + 2.0]) {
  237. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, 0, 0);
  238. }
  239. // to dome
  240. translate([0, 0, height + 2.0]) {
  241. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, ang/2, 0);
  242. }
  243. }
  244. // lower windscreen frame
  245. module sphear_lower_windscreen(sides, height, radius, beam_radius, conn_radius, pin_height, connectors = true) {
  246. ang = 360 / sides;
  247. // frame
  248. rotate([0, 0, ang/2]) {
  249. sphear_windscreen_frame(sides, height, radius, beam_radius, 45);
  250. }
  251. // frame crossing reinforcements
  252. rotate([0, 0, ang/2]) {
  253. // first mid crossing
  254. translate([0, 0, height/3]) {
  255. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, ang/2, 0);
  256. }
  257. // second mid crossing
  258. translate([0, 0, height*2/3]) {
  259. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, 0, 0);
  260. }
  261. }
  262. // connector to upper frame
  263. for (r = [1:ang:360]) rotate([0, 0, r]) {
  264. translate([radius, -beam_radius/2, height - 1.0 + 0.4]) {
  265. render() {
  266. difference() {
  267. sphere(r = conn_radius, $fn = facets);
  268. translate([-2 * conn_radius, -2 * conn_radius, (beam_radius) / 2]) {
  269. cube([4 * conn_radius, 4 * conn_radius, 4 * conn_radius]);
  270. }
  271. }
  272. // pin
  273. cylinder(r = beam_radius - fit, h = pin_height, $fn = facets);
  274. }
  275. }
  276. }
  277. // mount to body
  278. sphear_windscreen_round_mount(windscreen_thread_height, windscreen_thread_radius, windscreen_radius, 2 * wall);
  279. }
  280. //
  281. // Render components
  282. //
  283. // upper windscreen
  284. module render_sphear_upper_windscreen(zoffset) {
  285. translate([0, 0, zoffset]) {
  286. sphear_upper_windscreen(windscreen_sides, windscreen_height, windscreen_radius,
  287. windscreen_beam_radius, windscreen_conn_radius, windscreen_pin_height, connectors = true);
  288. }
  289. }
  290. // lower windscreen
  291. module render_sphear_lower_windscreen(zoffset) {
  292. translate([0, 0, zoffset]) {
  293. sphear_lower_windscreen(windscreen_sides, windscreen_height, windscreen_radius,
  294. windscreen_beam_radius, windscreen_conn_radius, windscreen_pin_height, connectors = true);
  295. }
  296. }
  297. // windscreen thread cover
  298. module render_sphear_windscreen_thread_cover(zoffset) {
  299. translate([0, 0, zoffset]) {
  300. sphear_windscreen_thread_cover(windscreen_thread_height, windscreen_thread_radius, wall);
  301. }
  302. }