1
0

SpHEAR_windscreen.scad 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. ////
  26. //// default model parameters
  27. ////
  28. // number of helixes of windscreen frame
  29. windscreen_sides = 12;
  30. // radius of windscreen beams
  31. windscreen_beam_radius = 1.3;
  32. // radius of frame connectors
  33. windscreen_conn_radius = windscreen_beam_radius + 0.8;
  34. // height of connector pin
  35. windscreen_pin_height = 4.0;
  36. // windscreen frame
  37. module sphear_windscreen_frame(sides, height, radius, beam_radius, twist) {
  38. inc = 360/sides;
  39. for (r = [0:inc:360]) for (t = [1, -1]) rotate([0, 0, r]) {
  40. render() {
  41. linear_extrude(height = height, center = false, convexity = 0, twist = twist * t, $fn = facets/2) {
  42. translate([radius, 0, 0]) {
  43. circle(r = beam_radius, $fn = facets/2);
  44. }
  45. }
  46. }
  47. }
  48. }
  49. // windscreen tapered frame
  50. module sphear_windscreen_tapered_frame(sides, height, radius, radius_h, beam_radius, twist) {
  51. echo(radius_h/radius);
  52. inc = 360/sides;
  53. for (r = [0:inc:360]) for (t = [1, -1]) rotate([0, 0, r]) {
  54. render() {
  55. linear_extrude(height = height, center = false, convexity = 0, twist = twist * t, scale = radius_h/radius, $fn = facets/2) {
  56. translate([radius, 0, 0]) {
  57. circle(r = beam_radius, $fn = facets/2);
  58. }
  59. }
  60. }
  61. }
  62. }
  63. // windscreen inset frame
  64. module sphear_windscreen_inset_frame(sides, height, radius, iradius, beam_radius, xscale = 1.0, yscale = 1.0) {
  65. inc = 360/sides;
  66. difference() {
  67. for (r = [0:inc:360]) for (t = [1, -1]) rotate([0, 0, r]) {
  68. render() {
  69. hull() {
  70. translate([iradius, 0, 0]) {
  71. scale([xscale, yscale, 1.0]) cylinder(r = beam_radius, h = thin_mint, $fn = facets / 2);
  72. }
  73. rotate([0, 0, inc/2 * t]) translate([radius, 0, height]) {
  74. cylinder(r = beam_radius, h = thin_mint, $fn = facets / 2);
  75. }
  76. }
  77. }
  78. }
  79. cylinder(r = iradius, h = height, $fn = facets);
  80. }
  81. }
  82. // windscreen frame reinforcements
  83. module sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, zrotation, yrotation) {
  84. for (r = [0:360/sides:360]) rotate([0, 0, r + zrotation]) {
  85. translate([radius, 0, 0]) {
  86. render() rotate([0, yrotation, 0]) intersection() {
  87. scale([1.0, 1.55, 1.0]) {
  88. translate([0, 0, -beam_radius * 2]) {
  89. cylinder(r = beam_radius, h = beam_radius * 4, $fn = facets);
  90. }
  91. }
  92. scale([1, 2, 2.5]) sphere(r = beam_radius, $fn = facets);
  93. }
  94. }
  95. }
  96. }
  97. // windscreen dome
  98. module sphear_windscreen_dome(sides, radius, beam_radius) {
  99. arcs = sides/2 - 1;
  100. ang = 360 / sides;
  101. difference() {
  102. for (r = [0, 90]) rotate([0, 0, r]) {
  103. for (t = [1, -1]) {
  104. translate([radius * sin(ang/2) * t, 0, 0]) rotate([0, 90, 0]) {
  105. render() rotate_extrude(convexity = 10, $fn = facets) {
  106. translate([radius * cos(ang/2), 0, 0]) {
  107. circle(r = beam_radius, $fn = facets);
  108. }
  109. }
  110. }
  111. translate([radius * sin(ang/(2/3)) * t, 0, 0]) rotate([0, 90, 0]) {
  112. render() rotate_extrude(convexity = 10, $fn = facets) {
  113. translate([radius * cos(ang/(2/3)), 0, 0]) {
  114. circle(r = beam_radius, $fn = facets);
  115. }
  116. }
  117. }
  118. }
  119. }
  120. brad = radius + 2 * beam_radius + thin_mint;
  121. translate([-brad, -brad, - 2 * brad]) {
  122. cube([2 * brad, 2 * brad, 2 * brad]);
  123. }
  124. }
  125. }
  126. // octagonal windscreen mount to body with thread
  127. module sphear_windscreen_mount(height, radius, beam_radius) {
  128. octagon_radius = (radius + 2 * beam_radius + wall) * cos(PI/8);
  129. difference() {
  130. cylinder(r = radius + 2 * beam_radius + windscreen_thread_depth, h = height, $fn = facets);
  131. metric_thread(diameter = radius * 2 + windscreen_thread_fit, pitch = windscreen_thread_pitch,
  132. length = height, angle = windscreen_thread_angle, internal = true);
  133. // make outside be a octagon instead of a circle
  134. rotate([0, 0, 22.5]) translate([0, 0, -thin_mint]) {
  135. difference() {
  136. cylinder(r = 1.5 * radius, h = height + 2 * thin_mint);
  137. cylinder(r = octagon_radius, h = height + 2 * thin_mint, $fn = 8);
  138. }
  139. }
  140. }
  141. // marker for center of screen
  142. translate([-(radius + wall), 0, 0]) {
  143. cylinder(r = 1.0, h = height, $fn = facets);
  144. }
  145. }
  146. // round windscreen mount to body with thread
  147. module sphear_windscreen_round_mount(height, radius, wradius, wall, knurl = false) {
  148. difference() {
  149. cylinder(r = radius + wall, h = height, $fn = facets);
  150. rotate([0, 0, -22.5/2]) metric_thread(diameter = radius * 2 + windscreen_thread_fit, pitch = windscreen_thread_pitch,
  151. length = height, angle = windscreen_thread_angle, internal = true);
  152. }
  153. // outer ring that attaches to windscreen
  154. difference() {
  155. union() {
  156. cylinder(r = wradius, h = height/2, $fn = facets);
  157. translate([0, 0, height/2]) {
  158. cylinder(r1 = wradius, r2 = radius + wall, h = height/2, $fn = facets);
  159. }
  160. }
  161. cylinder(r = radius + wall, h = height, $fn = facets);
  162. if (knurl) {
  163. for (r = [0:45/4:360]) rotate([0, 0, r]) {
  164. translate([radius + 2 * wall + 1.0 - 0.4, 0, 0]) scale([1.0, 1.5, 1]) cylinder(r = 2.0, h = height, $fn = facets);
  165. }
  166. }
  167. }
  168. // marker for center of microphone
  169. translate([-(wradius), 0, 0]) {
  170. cylinder(r = 1.0, h = height/2, $fn = facets);
  171. }
  172. }
  173. // round windscreen thread cover
  174. module sphear_windscreen_thread_cover(height, radius, wall) {
  175. difference() {
  176. cylinder(r = radius + 2 * wall, h = height, $fn = facets);
  177. metric_thread(diameter = radius * 2 + windscreen_thread_fit, pitch = windscreen_thread_pitch,
  178. length = height + thin_mint, angle = windscreen_thread_angle, internal = true);
  179. }
  180. // smooth transition to flare
  181. *translate([0, 0, height/2]) {
  182. difference() {
  183. translate([0, 0, height/2]) {
  184. cylinder(r2 = radius - windscreen_thread_depth/2, r1 = radius + 2 * wall, h = height/3, $fn = facets);
  185. }
  186. cylinder(r2 = radius - windscreen_thread_depth, r1 = radius + wall, h = height, $fn = facets);
  187. }
  188. }
  189. }
  190. // upper windscreen frame
  191. module sphear_upper_windscreen(sides, height, radius, beam_radius, conn_radius, pin_height, connectors = true) {
  192. ang = 360 / sides;
  193. // dome at top
  194. translate([0, 0, height]) {
  195. sphear_windscreen_dome(sides, radius, beam_radius);
  196. }
  197. // spiral wireframe
  198. translate([0, 0, 2]) {
  199. difference() {
  200. sphear_windscreen_frame(sides, height, radius, beam_radius, 45);
  201. if (connectors) {
  202. // remove bottom of beams to make space for the connectors
  203. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  204. translate([radius, -beam_radius/2, 0]) {
  205. cylinder(r = conn_radius, h = pin_height - 1.0, $fn = facets);
  206. }
  207. }
  208. }
  209. }
  210. }
  211. if (connectors) {
  212. // connectors to lower frame
  213. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  214. translate([radius, -beam_radius/2, 0]) {
  215. difference() {
  216. union() {
  217. cylinder(r = conn_radius, h = pin_height + 1.0, $fn = facets);
  218. translate([0, 0, pin_height + 1]) {
  219. sphere(r = conn_radius, $fn = facets);
  220. }
  221. }
  222. cylinder(r = beam_radius + fit, h = pin_height + 0.5, $fn = facets);
  223. }
  224. }
  225. }
  226. // bottom ring, prevents connectors to lower frame from toppling when printing
  227. difference() {
  228. scale([1.0, 1.0, 1.85]) rotate_extrude(convexity = 10, $fn = facets/2) {
  229. translate([radius, 0, 0]) {
  230. circle(r = beam_radius * 1.25, $fn = facets/2);
  231. }
  232. }
  233. translate([0, 0, -4 * beam_radius]) {
  234. cylinder(r = radius + beam_radius * 1.25, h = 4 * beam_radius + thin_mint, $fn = facets/2);
  235. }
  236. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  237. translate([radius, -beam_radius/2, -2]) {
  238. cylinder(r = conn_radius - thin_mint, h = 6.0 + thin_mint, $fn = facets/2);
  239. }
  240. }
  241. }
  242. // workaround for adhesion problems to the build plate (hack)
  243. // build a ring
  244. r_h = 0.4;
  245. difference() {
  246. cylinder(r = radius + 8 * wall, h = r_h, $fn = facets/2);
  247. translate([0, 0, -2*thin_mint]) cylinder(r = radius + 4 * wall, h = r_h + 4 * thin_mint, $fn = facets/2);
  248. }
  249. // and connect it to the windscreen
  250. for (r = [1:360/sides:360]) rotate([0, 0, r]) {
  251. translate([radius + conn_radius - beam_radius/2, -1, 0]) {
  252. cube([4 * wall, 1, r_h]);
  253. }
  254. }
  255. for (r = [360/(sides*2):360/sides:360]) rotate([0, 0, r]) {
  256. translate([radius + wall, -1, 0]) {
  257. cube([4 * wall, 1, r_h]);
  258. }
  259. }
  260. }
  261. // crossing reinforcements
  262. // first mid crossing
  263. translate([0, 0, height/3 + 2.0]) {
  264. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, ang/2, 0);
  265. }
  266. // second mid crossing
  267. translate([0, 0, height*2/3 + 2.0]) {
  268. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, 0, 0);
  269. }
  270. // to dome
  271. translate([0, 0, height + 2.0]) {
  272. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, ang/2, 0);
  273. }
  274. }
  275. // lower windscreen frame
  276. module sphear_lower_windscreen(sides, height, radius, beam_radius, conn_radius, pin_height, connectors = true) {
  277. ang = 360 / sides;
  278. // frame
  279. rotate([0, 0, ang/2]) {
  280. sphear_windscreen_frame(sides, height, radius, beam_radius, 45);
  281. }
  282. // frame crossing reinforcements
  283. rotate([0, 0, ang/2]) {
  284. // first mid crossing
  285. translate([0, 0, height/3]) {
  286. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, ang/2, 0);
  287. }
  288. // second mid crossing
  289. translate([0, 0, height*2/3]) {
  290. sphear_windscreen_frame_reinforcements(sides, radius, beam_radius, 0, 0);
  291. }
  292. }
  293. // connector to upper frame
  294. for (r = [1:ang:360]) rotate([0, 0, r]) {
  295. translate([radius, -beam_radius/2, height - 1.0 + 0.4]) {
  296. render() {
  297. difference() {
  298. sphere(r = conn_radius, $fn = facets);
  299. translate([-2 * conn_radius, -2 * conn_radius, (beam_radius) / 2]) {
  300. cube([4 * conn_radius, 4 * conn_radius, 4 * conn_radius]);
  301. }
  302. }
  303. // pin
  304. cylinder(r = beam_radius - fit, h = pin_height, $fn = facets);
  305. }
  306. }
  307. }
  308. // mount to body
  309. sphear_windscreen_round_mount(windscreen_thread_height, windscreen_thread_radius, windscreen_radius, 2 * wall);
  310. }
  311. // lower windscreen frame with inset
  312. module sphear_lower_tapered_windscreen(sides, height, radius, radius_h, beam_radius, conn_radius, pin_height, connectors = true) {
  313. ang = 360 / sides;
  314. // frame
  315. rotate([0, 0, ang/2]) {
  316. sphear_windscreen_tapered_frame(sides, height, radius, radius_h, beam_radius, 45);
  317. }
  318. // frame crossing reinforcements
  319. rotate([0, 0, ang/2]) {
  320. // first mid crossing
  321. translate([0, 0, height/3]) {
  322. sphear_windscreen_frame_reinforcements(sides, radius * (radius_h/radius*0.84), beam_radius, ang/2, 0);
  323. }
  324. // second mid crossing
  325. translate([0, 0, height*2/3]) {
  326. sphear_windscreen_frame_reinforcements(sides, radius * (radius_h/radius*0.92), beam_radius, 0, 0);
  327. }
  328. }
  329. // connector to upper frame
  330. for (r = [1:ang:360]) rotate([0, 0, r]) {
  331. translate([radius * (radius_h/radius), -beam_radius/2, height - 1.0 + 0.4]) {
  332. render() {
  333. difference() {
  334. sphere(r = conn_radius, $fn = facets);
  335. translate([-2 * conn_radius, -2 * conn_radius, (beam_radius) / 2]) {
  336. cube([4 * conn_radius, 4 * conn_radius, 4 * conn_radius]);
  337. }
  338. }
  339. // pin
  340. cylinder(r = beam_radius - fit, h = pin_height, $fn = facets);
  341. }
  342. }
  343. }
  344. // mount to body
  345. sphear_windscreen_round_mount(windscreen_thread_height, windscreen_thread_radius, windscreen_radius - 1.75, 2 * wall);
  346. }
  347. //
  348. // Render components
  349. //
  350. // upper windscreen
  351. module render_sphear_upper_windscreen(windscreen_radius, zoffset) {
  352. translate([0, 0, zoffset]) {
  353. sphear_upper_windscreen(windscreen_sides, windscreen_height, windscreen_radius,
  354. windscreen_beam_radius, windscreen_conn_radius, windscreen_pin_height, connectors = true);
  355. }
  356. }
  357. // lower windscreen
  358. module render_sphear_lower_windscreen(windscreen_radius, zoffset) {
  359. translate([0, 0, zoffset]) {
  360. sphear_lower_windscreen(windscreen_sides, windscreen_height, windscreen_radius,
  361. windscreen_beam_radius, windscreen_conn_radius, windscreen_pin_height, connectors = true);
  362. }
  363. }
  364. // lower windscreen
  365. module render_sphear_lower_tapered_windscreen(windscreen_radius_l, windscreen_radius_u, zoffset) {
  366. translate([0, 0, zoffset]) {
  367. sphear_lower_tapered_windscreen(windscreen_sides, windscreen_height, windscreen_radius_l, windscreen_radius_u,
  368. windscreen_beam_radius, windscreen_conn_radius, windscreen_pin_height, connectors = true);
  369. }
  370. }
  371. // windscreen thread cover
  372. module render_sphear_windscreen_thread_cover(zoffset) {
  373. translate([0, 0, zoffset]) {
  374. sphear_windscreen_thread_cover(windscreen_thread_height, windscreen_thread_radius, wall);
  375. }
  376. }