Octathingy_mount_pcb.scad 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611
  1. ////
  2. // Spherical Harmonics Ear Project (*SpHEAR)
  3. //
  4. // OctaSpHEAR or Octathingy, Second Order Ambisonics Microphone
  5. //
  6. // based on:
  7. // "A second-order soundfield microphone with improved polar pattern shape"
  8. // by Eric Benjamin, Audio Engineering Society Convention Paper 8728,
  9. // October 2012, San Francisco
  10. //
  11. // Copyright 2015-2019, Fernando Lopez-Lezcano, All Rights Reserved
  12. // nando@ccrma.stanford.edu
  13. //
  14. // This program is free software: you can redistribute it and/or modify
  15. // it under the terms of the GNU General Public License as published by
  16. // the Free Software Foundation, either version 3 of the License, or
  17. // (at your option) any later version.
  18. //
  19. // This program is distributed in the hope that it will be useful,
  20. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22. // GNU General Public License for more details.
  23. //
  24. // You should have received a copy of the GNU General Public License
  25. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  26. //
  27. // 3d Models released under the Creative Commons license as follows:
  28. // Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)
  29. // http://creativecommons.org/licenses/by-nc-sa/4.0/
  30. // d-sub connector
  31. include <db25.scad>;
  32. ////
  33. //// default model parameters
  34. ////
  35. // capsule array mount, height of flare and stalk
  36. flare_height = 50;
  37. stalk_height = 60;
  38. // calculated minimum "radius" of microphone box
  39. box_radius = pcb_front + (pcb_thickness + pcb_tfit) + pcb_back + 2 * wall;
  40. // calculated main body corner radius
  41. mount_corner = box_radius - pcb_width / 2 + pcb_slot_depth + 4.0;
  42. // body parameters
  43. render_screw_holes = true;
  44. radial_pcb_offset = pcb_version == 2 ? 15.0 : 17.0;
  45. octa_pcb_mount_height = pcb_length - pcb_low_exp - pcb_hi_exp;
  46. octa_pcb_wall = (pcb_version == 2 ? 4.75 : 5) * wall;
  47. // windscreen thread offset
  48. octa_pcb_thread_offset = (pcb_version == 2 ? -1.82 : 0.0);
  49. octa_pcb_radius = radial_pcb_offset + pcb_width/2 + octa_pcb_wall;
  50. // shock mount parameters
  51. //
  52. internal_ring_height = 55.0;
  53. external_ring_height = 10.0;
  54. rubber_band_angle = 45;
  55. main_radius_inc = (internal_ring_height / 2) / tan(rubber_band_angle);
  56. // gap between internal ring and microphone body
  57. internal_ring_gap = 1.0;
  58. // connector that joins the two internal rings
  59. connector_w = 10.0;
  60. connector_d = 2.0;
  61. // wall thickness and height of shock mount rings
  62. ring_wall = 4 * wall;
  63. ring_ext_height = 6;
  64. // gap between external ring and support arm
  65. ring_arm_gap = 16;
  66. // the main body that holds the phantom power interfaces
  67. module one_pcb_slot_old (height, pcb_w, pcb_l, pcb_t, pcb_offset, slot_d, front, back, test = false) {
  68. d = pcb_t + front + back;
  69. render() translate([-(pcb_w/2 + wall/2), -back, 0]) {
  70. // make cage with slots for pcb
  71. difference() {
  72. translate([-2 * wall, 0, 0]) {
  73. cube([pcb_w + 4 * wall, d, height]);
  74. }
  75. translate([slot_d, 0, 0]) {
  76. cube([pcb_w - 2 * slot_d, pcb_t + front + back, height]);
  77. }
  78. translate([0, back, 0]) {
  79. cube([pcb_w, pcb_t, height]);
  80. }
  81. // make top and bottom entry channels
  82. translate([slot_d, back + pcb_t/2, 0]) {
  83. rotate([0, 0, 45]) cylinder(r1 = pcb_t * 1.1, r2 = 0, h = 8.0, $fn = 4);
  84. }
  85. translate([pcb_w - slot_d, back + pcb_t/2, 0]) {
  86. rotate([0, 0, 45]) cylinder(r1 = pcb_t * 1.1, r2 = 0, h = 8.0, $fn = 4);
  87. }
  88. translate([slot_d, back + pcb_t/2, height - 8.0]) {
  89. rotate([0, 0, 45]) cylinder(r2 = pcb_t * 1.1, r1 = 0, h = 8.0, $fn = 4);
  90. }
  91. translate([pcb_w - slot_d, back + pcb_t/2, height - 8.0]) {
  92. rotate([0, 0, 45]) cylinder(r2 = pcb_t * 1.1, r1 = 0, h = 8.0, $fn = 4);
  93. }
  94. }
  95. // add spar in the back
  96. translate([-2 * wall, -back + wall, 0]) {
  97. cube([pcb_w + 4 * wall, wall, height]);
  98. }
  99. // pcb for testing fit
  100. if (test) {
  101. translate([0, back, pcb_offset]) {
  102. cube([pcb_w, pcb_t, pcb_l]);
  103. }
  104. // small electrolytic capacitors (pcb_version == 2)
  105. // https://www.mouser.com/datasheet/2/293/e-umw-1219455.pdf
  106. cap_diam = 8.0;
  107. // should be 5, but transistors are a bit taller;
  108. cap_len = 6.0;
  109. translate([pcb_w/2, pcb_t + cap_diam + 0.15, 6]) {
  110. rotate([90, 0, 0]) cylinder(r = (cap_diam/2), h = cap_len, $fn = facets);
  111. }
  112. // film capacitors
  113. cap_h = 12;
  114. cap_w = 9;
  115. cap_t = 5.5;
  116. translate([pcb_w/2 - cap_w/2, pcb_t + 0.15, 10]) {
  117. cube([cap_w, cap_t, cap_h]);
  118. }
  119. }
  120. }
  121. // add capacitor if in test mode
  122. *if (test) {
  123. cap_diam = 10.2;
  124. translate([0, cap_diam/2 + pcb_t, 0]) {
  125. cylinder(r = cap_diam/2, h = 20, $fn = facets);
  126. }
  127. }
  128. }
  129. // one printed circuit board with space in the back and front
  130. module one_pcb_slot (height, pcb_w, pcb_l, pcb_t, pcb_offset, slot_d, front, back, test = false) {
  131. render() translate([-(pcb_w/2 + 0.5), 0, 0]) {
  132. // printed circuit board with space for solder and components
  133. cube([pcb_w, pcb_t, pcb_l]);
  134. // open space in back and front
  135. // tune front and back by hand
  136. translate([slot_d, -2.0, 0]) cube([pcb_w - (2.0 * slot_d), 15, pcb_l]);
  137. // make top and bottom entry channels
  138. translate([slot_d, pcb_t/2, 0]) {
  139. rotate([0, 0, 45]) cylinder(r1 = pcb_t * 1.1, r2 = 0, h = 8.0, $fn = 4);
  140. }
  141. translate([pcb_w - slot_d, pcb_t/2, 0]) {
  142. rotate([0, 0, 45]) cylinder(r1 = pcb_t * 1.1, r2 = 0, h = 8.0, $fn = 4);
  143. }
  144. translate([slot_d, pcb_t/2, height - 8.0]) {
  145. rotate([0, 0, 45]) cylinder(r2 = pcb_t * 1.1, r1 = 0, h = 8.0, $fn = 4);
  146. }
  147. translate([pcb_w - slot_d, pcb_t/2, height - 8.0]) {
  148. rotate([0, 0, 45]) cylinder(r2 = pcb_t * 1.1, r1 = 0, h = 8.0, $fn = 4);
  149. }
  150. }
  151. }
  152. // the partition that connects inner and outer sections of body
  153. module one_pcb_parts (height, pcb_w, pcb_l, pcb_t, pcb_offset, slot_d, front, back) {
  154. //render() translate([-(pcb_w/2 + wall), -(back + wall), 0]) {
  155. render() translate([-(pcb_w/2 + 0.5), 0, 0]) {
  156. // printed circuit board
  157. translate([0, 0, pcb_offset]) cube([pcb_w, pcb_t, pcb_l]);
  158. // small electrolytic capacitors (pcb_version == 2)
  159. // https://www.mouser.com/datasheet/2/293/e-umw-1219455.pdf
  160. cap_diam = 8.0;
  161. // should be 5, but transistors are a bit taller;
  162. cap_len = 6.0;
  163. translate([pcb_w/2, cap_len + pcb_t, 6]) {
  164. rotate([90, 0, 0]) cylinder(r = (cap_diam/2), h = cap_len, $fn = facets);
  165. }
  166. // film capacitors
  167. cap_h = 12;
  168. cap_w = 9;
  169. cap_t = 5.5;
  170. translate([pcb_w/2 - cap_w/2, pcb_t, 10]) {
  171. cube([cap_w, cap_t, cap_h]);
  172. }
  173. }
  174. }
  175. module rounded_octagon(height, radius) {
  176. intersection() {
  177. cylinder(r = radius, h = height, $fn = 8);
  178. cylinder(r = radius - wall, h = height + thin_mint, $fn = facets);
  179. }
  180. }
  181. module rounded_octagon_wall(height, radius, wall) {
  182. difference() {
  183. rounded_octagon(height, radius);
  184. rounded_octagon(height + thin_mint, radius - wall);
  185. }
  186. }
  187. // twist angle to optimize space usage inside body
  188. //octa_pcb_twist = pcb_version == 2 ? 12 : 16;
  189. octa_pcb_twist = pcb_version == 2 ? 13.5 : 16;
  190. // tilt angle to clear upper flare thread
  191. octa_pcb_tilt = pcb_version == 2 ? -0.7 : 0.0;
  192. module octa_mount_body_old(height, radius, lower_lip, upper_lip, clear) {
  193. // rotate pcb assembly so it does not interfere with the screws
  194. offset_angle = -octa_pcb_twist;
  195. // rotate individual pcb's to better use the internal space of the body
  196. twist_angle = octa_pcb_twist;
  197. difference() {
  198. union() {
  199. difference() {
  200. union() {
  201. // main body
  202. rounded_octagon_wall(height, radius, 2 * wall);
  203. // slots for printed circuit boards
  204. intersection() {
  205. for (r = [0:360/8:360]) rotate([0, octa_pcb_tilt, r + offset_angle]) {
  206. translate([radial_pcb_offset, 0, 0]) {
  207. rotate([0, 0, 180 + twist_angle]) {
  208. one_pcb_slot(height * 2/3, pcb_width + pcb_fit, pcb_length, pcb_thickness + pcb_tfit, -10,
  209. pcb_slot_depth, pcb_front, pcb_back, false);
  210. }
  211. }
  212. }
  213. // clip outside
  214. rounded_octagon(height, radius);
  215. }
  216. }
  217. // upper lip for flare to microphone
  218. translate([0, 0, height - upper_lip]) {
  219. rounded_octagon_wall(upper_lip, radius, wall + lip_fit);
  220. }
  221. // lower lip for flare to cable or connector
  222. translate([0, 0, 0]) {
  223. rounded_octagon_wall(upper_lip, radius, wall + lip_fit);
  224. }
  225. }
  226. if (render_screw_holes) {
  227. // add backplates for upper lip screws
  228. for (r = [45, 135, 225, 315]) {
  229. rotate([0, 0, r]) translate([-(radius - 3 * wall), -2.5, 0]) {
  230. cube([2, 5, height]);
  231. }
  232. }
  233. }
  234. }
  235. if (render_screw_holes) {
  236. // make eight holes in the the body for screws that hold both flares
  237. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  238. difference() {
  239. for (z = [lower_lip/2, height - upper_lip/2]) {
  240. for (r = [45, 135, 225, 315]) {
  241. rotate([0, 0, r]) translate([-(radius + 2 * wall), 0, z]) {
  242. rotate([0, 90, 0]) {
  243. cylinder(r = 0.7, h = radius + wall, $fn = facets);
  244. }
  245. }
  246. }
  247. }
  248. cylinder(r = radius/2, h = height);
  249. }
  250. }
  251. }
  252. }
  253. module octa_mount_body(height, radius, lower_lip, upper_lip, clear) {
  254. // rotate pcb assembly so it does not interfere with the screws
  255. offset_angle = -octa_pcb_twist;
  256. // rotate individual pcb's to better use the internal space of the body
  257. twist_angle = octa_pcb_twist;
  258. difference() {
  259. union() {
  260. difference() {
  261. union() {
  262. // main body
  263. rounded_octagon_wall(height, radius, 2 * wall);
  264. difference() {
  265. // fill the inside of the body
  266. translate([0, 0, -1]) rounded_octagon(height * 2/3, radius);
  267. // remove everything else
  268. union() {
  269. translate([0, 0, -1]) for (r = [0:360/8:360]) rotate([0, octa_pcb_tilt, r + offset_angle]) {
  270. translate([radial_pcb_offset, 0, 0]) {
  271. rotate([0, 0, 180 + twist_angle]) {
  272. one_pcb_slot(height * 2/3, pcb_width + pcb_fit, pcb_length, pcb_thickness + pcb_tfit, -10,
  273. pcb_slot_depth, pcb_front, pcb_back);
  274. }
  275. }
  276. }
  277. // make center hole
  278. cylinder(r = 6.0, h = height, $fn = facets);
  279. }
  280. }
  281. translate([0, 0, -1]) for (r = [0:360/8:360]) rotate([0, octa_pcb_tilt, r + offset_angle]) {
  282. translate([radial_pcb_offset, 0, 0]) {
  283. rotate([0, 0, 180 + twist_angle]) {
  284. // add wall that connects core with outer shell
  285. translate([-(pcb_width/2 + 2 * wall), -(wall + pcb_back), 0]) {
  286. cube([pcb_width + 2 * wall, wall, height * 2/3]);
  287. }
  288. // add components if we are testing for fit
  289. *one_pcb_parts(height * 2/3, pcb_width + pcb_fit, pcb_length, pcb_thickness + pcb_tfit, -10,
  290. pcb_slot_depth, pcb_front, pcb_back);
  291. }
  292. }
  293. }
  294. }
  295. // clip inside of body below body (we need this because of pcb tilt)
  296. translate([0, 0, -2.0]) rounded_octagon(2.0, radius);
  297. // upper lip for flare to microphone
  298. translate([0, 0, height - upper_lip]) {
  299. rounded_octagon_wall(upper_lip, radius, wall + lip_fit);
  300. }
  301. // lower lip for flare to cable or connector
  302. translate([0, 0, 0]) {
  303. rounded_octagon_wall(upper_lip, radius, wall + lip_fit);
  304. }
  305. }
  306. if (render_screw_holes) {
  307. // add backplates for upper lip screws
  308. for (r = [45, 135, 225, 315]) {
  309. rotate([0, 0, r]) translate([-(radius - 3 * wall), -2.5, 0]) {
  310. cube([2, 5, height]);
  311. }
  312. }
  313. }
  314. }
  315. if (render_screw_holes) {
  316. // make eight holes in the the body for screws that hold both flares
  317. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  318. difference() {
  319. for (z = [lower_lip/2, height - upper_lip/2]) {
  320. for (r = [45, 135, 225, 315]) {
  321. rotate([0, 0, r]) translate([-(radius + 2 * wall), 0, z]) {
  322. rotate([0, 90, 0]) {
  323. cylinder(r = 0.7, h = radius + wall, $fn = facets);
  324. }
  325. }
  326. }
  327. }
  328. cylinder(r = radius/2, h = height);
  329. }
  330. }
  331. }
  332. }
  333. // flare from the body to the microphone stalk
  334. module octa_mount_flare_no_ws(height, lip, transition, radius, top_radius, stalk_height, dot) {
  335. // bottom box
  336. difference() {
  337. union() {
  338. rounded_octagon_wall(height, radius, 2 * wall);
  339. if (render_screw_holes) {
  340. // small pedestals for the screws that attach the flare to the body
  341. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  342. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  343. translate([radius - wall - 1.75, 0, lip/2]) {
  344. rotate([0, 90, 0]) {
  345. cylinder(r = 1.5, h = 2 * wall, $fn = facets);
  346. }
  347. }
  348. }
  349. }
  350. }
  351. // flange to mount on body
  352. rounded_octagon_wall(lip + 1.00, radius - wall, wall);
  353. // and make a smooth transition to avoid overhangs
  354. translate([0, 0, lip + 1.00]) {
  355. hull() {
  356. rounded_octagon_wall(thin_mint, radius - wall, wall);
  357. translate([0, 0, 1.0]) {
  358. rounded_octagon_wall(thin_mint, radius - 2 * wall, wall);
  359. }
  360. }
  361. }
  362. if (render_screw_holes) {
  363. // holes for screws that attach the flare to the body
  364. // Number 0 Size, 1/4" Long = thread diameter: 1.6mm, head diameter: 2.75
  365. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  366. translate([radius/2, 0, lip/2]) {
  367. rotate([0, 90, 0]) {
  368. cylinder(r = (1.6 + 0.1)/2, h = radius, $fn = facets);
  369. }
  370. }
  371. }
  372. }
  373. }
  374. // flare to round section
  375. translate([0, 0, height]) {
  376. difference() {
  377. hull() {
  378. rounded_octagon(thin_mint, radius);
  379. translate([0, 0, transition]) {
  380. cylinder(r = top_radius, h = thin_mint, $fn = facets);
  381. }
  382. }
  383. hull() {
  384. rounded_octagon(thin_mint, radius - wall);
  385. translate([0, 0, transition]) {
  386. cylinder(r = top_radius - wall, h = thin_mint, $fn = facets);
  387. }
  388. }
  389. }
  390. }
  391. // cylindrical stalk
  392. translate([0, 0, height + transition]) {
  393. difference() {
  394. cylinder(r = top_radius, h = stalk_height, $fn = facets);
  395. cylinder(r = top_radius - wall, h = stalk_height, $fn = facets);
  396. }
  397. // add marker for "back of microphone" orientation
  398. if (dot == 1) {
  399. rotate([0, 0, 90]) {
  400. translate([0, top_radius - wall * 2 / 3, stalk_height - top_radius]) {
  401. difference() {
  402. sphere(r = top_radius / 3, $fn = 32);
  403. translate([0, -top_radius + top_radius / 2, 0]) {
  404. cube([top_radius, top_radius, top_radius], center = true);
  405. }
  406. }
  407. }
  408. }
  409. }
  410. // close stalk and add holes for cables
  411. translate([0, 0, stalk_height - top_radius - wall]) {
  412. difference() {
  413. cylinder(r = top_radius - wall, h = top_radius + wall, $fn = facets);
  414. translate([0, 0, 0]) {
  415. sphere(r = top_radius - wall, $fn = facets);
  416. }
  417. wire_diam = mic_wire_diam + mic_wire_fit;
  418. for (r = [0, 90, 180, 270]) rotate([0, 0, r]) {
  419. for (t = [0, 1]) {
  420. rotate([0, 0, 45 * t]) translate([top_radius - wire_diam - t * wire_diam * 2/3, 0, wall]) {
  421. cylinder(r = wire_diam / 2, h = top_radius * 2, $fn = facets);
  422. }
  423. }
  424. }
  425. translate([0, 0, wall]) cylinder(r = wire_diam, h = top_radius * 2, $fn = facets);
  426. }
  427. }
  428. }
  429. }
  430. module octa_mount_flare_old(height, lip, transition, radius, top_radius, stalk_height, dot) {
  431. // transition from bottom box to windscreen mounting thread
  432. transition_to_threads = 5;
  433. // bottom box
  434. difference() {
  435. union() {
  436. rounded_octagon_wall(height, radius, 2 * wall);
  437. if (render_screw_holes) {
  438. // small pedestals for the screws that attach the flare to the body
  439. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  440. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  441. translate([radius - wall - 1.75, 0, lip/2]) {
  442. rotate([0, 90, 0]) {
  443. cylinder(r = 1.5, h = 2 * wall, $fn = facets);
  444. }
  445. }
  446. }
  447. }
  448. // indicator of "front" of microphone
  449. rotate([0, 0, 180 + 22.5]) translate([radius - 2, 0, 0]) {
  450. cylinder(r = 1.0, h = lip/2, $fn = facets);
  451. }
  452. // stops for shock mount
  453. for (r = [0, 90, 180, 270]) rotate([0, 0, r - 22.5]) {
  454. translate([radius - 3.4, 0, 0]) scale([2.0, 1.0, 1.0]) {
  455. difference() {
  456. cylinder(r = 2.0, h = lip + transition_to_threads, $fn = facets);
  457. translate([-2, -2.0, 0]) cube([2.0, 4.0, lip + transition_to_threads]);
  458. }
  459. }
  460. }
  461. }
  462. // flange to mount on body
  463. rounded_octagon_wall(lip + 1.00, radius - wall, wall);
  464. // and make a smooth transition to avoid overhangs
  465. translate([0, 0, lip + 1.00]) {
  466. hull() {
  467. rounded_octagon_wall(thin_mint, radius - wall, wall);
  468. translate([0, 0, 1.0]) {
  469. rounded_octagon_wall(thin_mint, radius - 2 * wall, wall);
  470. }
  471. }
  472. }
  473. if (render_screw_holes) {
  474. // holes for screws that attach the flare to the body
  475. // Number 0 Size, 1/4" Long = thread diameter: 1.6mm, head diameter: 2.75
  476. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  477. translate([radius/2, 0, lip/2]) {
  478. rotate([0, 90, 0]) {
  479. cylinder(r = (1.6 + 0.1)/2, h = radius, $fn = facets);
  480. }
  481. }
  482. }
  483. }
  484. }
  485. // flare to windscreen threads
  486. translate([0, 0, height - windscreen_thread_height - transition_to_threads]) {
  487. difference() {
  488. hull() {
  489. rounded_octagon(thin_mint, radius);
  490. translate([0, 0, transition_to_threads]) {
  491. cylinder(r = windscreen_thread_radius + 0.5, h = thin_mint, $fn = facets);
  492. }
  493. }
  494. hull() {
  495. rounded_octagon(thin_mint, radius - wall);
  496. translate([0, 0, transition_to_threads]) {
  497. cylinder(r = windscreen_thread_radius - windscreen_thread_depth - wall, h = thin_mint, $fn = facets);
  498. }
  499. }
  500. }
  501. }
  502. // windscreen mounting threads
  503. translate([0, 0, height - windscreen_thread_height]) difference() {
  504. metric_thread(diameter = windscreen_thread_radius * 2, pitch = windscreen_thread_pitch,
  505. length = windscreen_thread_height, angle = windscreen_thread_angle, internal = false);
  506. cylinder(r = windscreen_thread_radius - wall - windscreen_thread_depth, h = windscreen_thread_height + thin_mint, $fn = facets);
  507. }
  508. // flare to stalk
  509. translate([0, 0, height - 1.5]) {
  510. difference() {
  511. hull() {
  512. cylinder(r = windscreen_thread_radius - windscreen_thread_depth, h = thin_mint, $fn = facets);
  513. translate([0, 0, transition + 1.5]) {
  514. cylinder(r = top_radius, h = thin_mint, $fn = facets);
  515. }
  516. }
  517. hull() {
  518. cylinder(r = windscreen_thread_radius - windscreen_thread_depth - wall, h = thin_mint, $fn = facets);
  519. translate([0, 0, transition + 1.5]) {
  520. cylinder(r = top_radius - wall, h = thin_mint, $fn = facets);
  521. }
  522. }
  523. }
  524. }
  525. // cylindrical stalk
  526. translate([0, 0, height + transition]) {
  527. difference() {
  528. cylinder(r = top_radius, h = stalk_height, $fn = facets);
  529. cylinder(r = top_radius - wall, h = stalk_height, $fn = facets);
  530. }
  531. // close stalk and add holes for cables
  532. translate([0, 0, stalk_height - top_radius - wall]) {
  533. difference() {
  534. cylinder(r = top_radius - wall, h = top_radius + wall, $fn = facets);
  535. translate([0, 0, 0]) {
  536. sphere(r = top_radius - wall, $fn = facets);
  537. }
  538. wire_diam = mic_wire_diam + mic_wire_fit;
  539. for (r = [0, 90, 180, 270]) rotate([0, 0, r]) {
  540. for (t = [0, 1]) {
  541. rotate([0, 0, 45 * t]) translate([top_radius - wire_diam - t * wire_diam * 2/3, 0, wall]) {
  542. cylinder(r = wire_diam / 2, h = top_radius * 2, $fn = facets);
  543. }
  544. }
  545. }
  546. translate([0, 0, wall]) cylinder(r = wire_diam, h = top_radius * 2, $fn = facets);
  547. }
  548. }
  549. }
  550. }
  551. // stalk from flare to capsule array mount
  552. module octa_mount_stalk(height, lip, transition, radius, top_radius, stalk_height, dot) {
  553. translate([0, 0, height + transition]) {
  554. translate ([0, 0, -10.0]) difference() {
  555. cylinder(r = top_radius, h = stalk_height + 10.0, $fn = facets);
  556. cylinder(r = top_radius - wall, h = stalk_height + 10.0, $fn = facets);
  557. }
  558. // close stalk and add holes for cables
  559. translate([0, 0, stalk_height - top_radius - wall]) {
  560. difference() {
  561. cylinder(r = top_radius - wall, h = top_radius + wall, $fn = facets);
  562. translate([0, 0, 0]) {
  563. sphere(r = top_radius - wall, $fn = facets);
  564. }
  565. wire_diam = mic_wire_diam + mic_wire_fit;
  566. for (r = [0, 90, 180, 270]) rotate([0, 0, r]) {
  567. for (t = [0, 1]) {
  568. rotate([0, 0, 45 * t]) translate([top_radius - wire_diam - t * wire_diam * 2/3, 0, wall]) {
  569. cylinder(r = wire_diam / 2, h = top_radius * 2, $fn = facets);
  570. }
  571. }
  572. }
  573. translate([0, 0, wall]) cylinder(r = wire_diam, h = top_radius * 2, $fn = facets);
  574. }
  575. }
  576. // add flange for coupling into flare
  577. difference() {
  578. cylinder(r2 = top_radius, r1 = top_radius + wall, h = 10.0, $fn = facets);
  579. cylinder(r2 = top_radius - wall, r1 = top_radius, h = 10.0, $fn = facets);
  580. }
  581. translate([top_radius, 0, -10.0]) {
  582. // add key to stalk so orientation is always correct
  583. difference() {
  584. cylinder(r = 0.4, h = 10.0, $fn = facets);
  585. }
  586. }
  587. }
  588. }
  589. // flare from body to capsule array stalk
  590. module octa_mount_flare(height, lip, transition, radius, top_radius, stalk_height, dot) {
  591. // transition from bottom box to windscreen mounting thread
  592. transition_to_threads = 5;
  593. // bottom box
  594. difference() {
  595. union() {
  596. rounded_octagon_wall(height - windscreen_thread_height, radius, 2 * wall);
  597. if (render_screw_holes) {
  598. // small pedestals for the screws that attach the flare to the body
  599. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  600. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  601. translate([radius - wall - 1.75, 0, lip/2]) {
  602. rotate([0, 90, 0]) {
  603. cylinder(r = 1.5, h = 2 * wall, $fn = facets);
  604. }
  605. }
  606. }
  607. }
  608. // indicator of "front" of microphone
  609. rotate([0, 0, 180 + 22.5]) translate([radius - 2, 0, 0]) {
  610. cylinder(r = 1.0, h = lip/3, $fn = facets);
  611. }
  612. // stops for shock mount
  613. for (r = [0, 90, 180, 270]) rotate([0, 0, r - 22.5]) {
  614. translate([radius - 3.4, 0, 0]) scale([2.0, 1.0, 1.0]) {
  615. difference() {
  616. // cylinder(r = 2.0, h = lip + transition_to_threads, $fn = facets);
  617. cylinder(r = 2.0, h = 5.0, $fn = facets);
  618. translate([-2, -2.0, 0]) cube([2.0, 4.0, lip + transition_to_threads]);
  619. }
  620. }
  621. }
  622. }
  623. // flange to mount on body
  624. rounded_octagon_wall(lip + 1.00, radius - wall, wall);
  625. // and make a smooth transition to avoid overhangs
  626. translate([0, 0, lip + 1.00]) {
  627. hull() {
  628. rounded_octagon_wall(thin_mint, radius - wall, wall);
  629. translate([0, 0, 1.0]) {
  630. rounded_octagon_wall(thin_mint, radius - 2 * wall, wall);
  631. }
  632. }
  633. }
  634. if (render_screw_holes) {
  635. // holes for screws that attach the flare to the body
  636. // Number 0 Size, 1/4" Long = thread diameter: 1.6mm, head diameter: 2.75
  637. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  638. translate([radius/2, 0, lip/2]) {
  639. rotate([0, 90, 0]) {
  640. cylinder(r = (1.6 + 0.1)/2, h = radius, $fn = facets);
  641. }
  642. }
  643. }
  644. }
  645. }
  646. // windscreen mounting threads
  647. translate([0, 0, height - windscreen_thread_height]) difference() {
  648. metric_thread(diameter = windscreen_thread_radius * 2, pitch = windscreen_thread_pitch,
  649. length = windscreen_thread_height, angle = windscreen_thread_angle, internal = false);
  650. cylinder(r = windscreen_thread_radius - wall - windscreen_thread_depth, h = windscreen_thread_height + thin_mint, $fn = facets);
  651. // clip thread tips
  652. difference() {
  653. cylinder(r = windscreen_thread_radius + wall, h = windscreen_thread_height + thin_mint, $fn = facets);
  654. cylinder(r = windscreen_thread_radius - windscreen_thread_depth * 0.3, h = windscreen_thread_height + thin_mint, $fn = facets);
  655. }
  656. }
  657. // flare to stalk
  658. translate([0, 0, height - 1.5]) {
  659. difference() {
  660. cylinder(r1 = windscreen_thread_radius - windscreen_thread_depth,
  661. r2 = top_radius + wall + fit, h = transition + 1.5, $fn = facets);
  662. cylinder(r1 = windscreen_thread_radius - windscreen_thread_depth - wall,
  663. r2 = top_radius + fit, h = transition + 1.5, $fn = facets);
  664. }
  665. }
  666. // socket for stalk
  667. s_length = 10.0;
  668. translate([0, 0, height + transition - s_length]) {
  669. difference() {
  670. cylinder(r = top_radius + wall + fit, h = s_length, $fn = facets);
  671. cylinder(r = top_radius + fit, h = s_length, $fn = facets);
  672. // add key slot for orientation
  673. translate([top_radius, 0, -1]) {
  674. cylinder(r = 0.4, h = s_length + 2, $fn = facets);
  675. }
  676. }
  677. }
  678. // internal flare for stalk
  679. translate([0, 0, height - 1.5]) {
  680. difference() {
  681. cylinder(r1 = windscreen_thread_radius - windscreen_thread_depth,
  682. r2 = top_radius + wall + fit, h = transition + 1.5 - s_length, $fn = facets);
  683. cylinder(r1 = windscreen_thread_radius - windscreen_thread_depth - wall,
  684. r2 = top_radius + fit, h = transition + 1.5 - s_length, $fn = facets);
  685. }
  686. }
  687. }
  688. // flare from the body to a dual cable housing
  689. module octa_mount_flare_dual(height, lip, transition, xradius, yradius, corner, top_radius, stalk_height) {
  690. // hack to get it to render, fix problem in rounded_block when radius is equal to corner...
  691. delta = 0.001;
  692. difference() {
  693. union() {
  694. // bottom rounded box
  695. difference() {
  696. rounded_block(height, xradius, yradius, corner);
  697. rounded_block_relative(height, xradius, yradius, corner, -(2 * wall));
  698. // flange to mount on body
  699. rounded_block_relative(lip + 1.00, xradius, yradius, corner, - (wall));
  700. // and make a smooth transition to avoid overhangs
  701. translate([0, 0, lip + 1.00]) {
  702. hull() {
  703. rounded_block_relative(thin_mint, xradius, yradius, corner, - wall);
  704. translate([0, 0, 1.0]) {
  705. rounded_block_relative(thin_mint, xradius, yradius, corner, - 2 * wall);
  706. }
  707. }
  708. }
  709. }
  710. // flare to rounded section
  711. translate([0, 0, height]) {
  712. difference() {
  713. hull() {
  714. rounded_block(thin_mint, xradius, yradius, corner);
  715. translate([0, 0, transition]) {
  716. rounded_block(thin_mint, top_radius + wall / 2, top_radius * 2 + wall / 2, top_radius - delta);
  717. }
  718. }
  719. hull() {
  720. rounded_block_relative(thin_mint, xradius, yradius, corner, - 2 * wall);
  721. translate([0, -top_radius, transition]) {
  722. cube([thin_mint, (top_radius) * 2, thin_mint]);
  723. }
  724. }
  725. }
  726. }
  727. // corner box cable stalk
  728. translate([0, 0, height + transition]) {
  729. rounded_block(stalk_height, top_radius + wall / 2, top_radius * 2 + wall / 2, top_radius - delta);
  730. }
  731. }
  732. // holes for the cables
  733. for (offset = [top_radius - wall/2, -(top_radius - wall/2)]) {
  734. translate([0, offset, 0]){
  735. cylinder(r = top_radius - wall, h = height + transition + stalk_height, $fn = facets);
  736. }
  737. }
  738. }
  739. }
  740. // flare from the body to a dual conector housing
  741. // bottom connector holder
  742. module tetra_mount_connector_holder(height, radius, inside_radius, sleeve_height, sleeve_radius) {
  743. difference() {
  744. union() {
  745. cylinder(r = radius, h = height, $fn = facets);
  746. // add seats for screw heads
  747. for (m = [-1, 1]) translate([m * conn_core_holes_w / 2, radius / 2, conn_core_holes_h]) {
  748. rotate([90, 0, 0]) {
  749. scale([1, 1, 1]) cylinder(r = conn_core_screw_d / 2, h = radius * 1.43, $fn = facets);
  750. }
  751. }
  752. }
  753. cylinder(r = inside_radius, h = height, $fn = facets);
  754. // transition from thin wall to thick wall at the bottom of connector
  755. *cylinder(r1 = radius - wall, r2 = inside_radius, h = 2.0, $fn = facets);
  756. // holes for connector core screws
  757. for (m = [-1, 1]) translate([m * conn_core_holes_w / 2, - radius / 3, conn_core_holes_h]) {
  758. rotate([90, 0, 0]) {
  759. cylinder(r = conn_core_holes_d / 2, h = radius, $fn = facets);
  760. }
  761. }
  762. // substract cutout for screw heads
  763. for (m = [-1, 1]) translate([m * conn_core_holes_w / 2, - radius + 1.5, conn_core_holes_h]) {
  764. rotate([90, 0, 0]) {
  765. cylinder(r = conn_core_screw_d / 2, h = 2.0, $fn = facets);
  766. }
  767. }
  768. }
  769. // thinner cylinder sits inside connector sleeve
  770. translate([0, 0, height]) {
  771. difference() {
  772. cylinder(r = sleeve_radius, h = sleeve_height, $fn = facets);
  773. cylinder(r = inside_radius, h = sleeve_height, $fn = facets);
  774. }
  775. }
  776. }
  777. // flare to dual cable connectors
  778. module octa_mount_flare_connector(height, lip, transition, radius, top_xradius, top_yradius) {
  779. // hack to get it to render, fix problem in rounded_block when radius is equal to corner...
  780. delta = 0.001;
  781. // bottom rounded box
  782. difference() {
  783. union() {
  784. rounded_octagon_wall(height, radius, 2 * wall);
  785. if (render_screw_holes) {
  786. // small pedestals for the screws that attach the flare to the body
  787. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  788. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  789. translate([radius - wall - 1.75, 0, lip/2]) {
  790. rotate([0, 90, 0]) {
  791. cylinder(r = 1.5, h = 2 * wall, $fn = facets);
  792. }
  793. }
  794. }
  795. }
  796. }
  797. // flange to mount on body
  798. rounded_octagon_wall(lip + 1.00, radius - wall, wall);
  799. // and make a smooth transition to avoid overhangs
  800. translate([0, 0, lip + 1.00]) {
  801. hull() {
  802. rounded_octagon_wall(thin_mint, radius - wall, wall);
  803. translate([0, 0, 1.0]) {
  804. rounded_octagon_wall(thin_mint, radius - 2 * wall, wall);
  805. }
  806. }
  807. }
  808. if (render_screw_holes) {
  809. // holes for screws that attach the flare to the body
  810. // Number 0 Size, 1/4" Long = thread diameter: 1.6mm, head diameter: 2.75
  811. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  812. translate([radius/2, 0, lip/2]) {
  813. rotate([0, 90, 0]) {
  814. cylinder(r = (1.6 + 0.1)/2, h = radius, $fn = facets);
  815. }
  816. }
  817. }
  818. }
  819. }
  820. // flare to rounded section
  821. translate([0, 0, height]) {
  822. difference() {
  823. hull() {
  824. rounded_octagon(thin_mint, radius);
  825. translate([0, 0, transition]) {
  826. rounded_block(thin_mint, top_xradius, top_yradius, top_xradius - delta);
  827. }
  828. }
  829. hull() {
  830. rounded_octagon(thin_mint, radius - 2 * wall);
  831. translate([0, -top_xradius, transition]) {
  832. cube([thin_mint, (top_xradius) * 2, thin_mint]);
  833. }
  834. }
  835. }
  836. }
  837. }
  838. // flare to d-sub 25 pin connector
  839. module octa_mount_flare_dsub(height, lip, transition, radius, top_xradius, top_yradius) {
  840. // bottom octagonal box
  841. difference() {
  842. union() {
  843. rounded_octagon_wall(height, radius, 2 * wall);
  844. if (render_screw_holes) {
  845. // small pedestals for the screws that attach the flare to the body
  846. // (number 0 size, 1/4" long = thread diameter: 1.6mm, head diameter: 2.75)
  847. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  848. translate([radius - wall - 1.75, 0, lip/2]) {
  849. rotate([0, 90, 0]) {
  850. cylinder(r = 1.5, h = 2 * wall, $fn = facets);
  851. }
  852. }
  853. }
  854. }
  855. }
  856. // flange to mount on body
  857. rounded_octagon_wall(lip + 1.00, radius - wall, wall);
  858. // and make a smooth transition to avoid overhangs
  859. translate([0, 0, lip + 1.00]) {
  860. hull() {
  861. rounded_octagon_wall(thin_mint, radius - wall, wall);
  862. translate([0, 0, 1.0]) {
  863. rounded_octagon_wall(thin_mint, radius - 2 * wall, wall);
  864. }
  865. }
  866. }
  867. if (render_screw_holes) {
  868. // holes for screws that attach the flare to the body
  869. // Number 0 Size, 1/4" Long = thread diameter: 1.6mm, head diameter: 2.75
  870. for (r = [45, 135, 225, 315]) rotate([0, 0, r]) {
  871. translate([radius/2, 0, lip/2]) {
  872. rotate([0, 90, 0]) {
  873. cylinder(r = (1.6 + 0.1)/2, h = radius, $fn = facets);
  874. }
  875. }
  876. }
  877. }
  878. }
  879. // flare to db25 connector mounting plate
  880. expand = pcb_version == 2 ? 1 : 3;
  881. // height of connector
  882. guard_height = 9.525;
  883. // thickness of db25 plate
  884. db25_t = 3 * wall;
  885. translate([0, 0, height]) {
  886. minkr = 2.0;
  887. difference() {
  888. hull() {
  889. rounded_octagon(thin_mint, radius);
  890. rotate([0, 0, -22.5]) translate([0, 0, transition - 5.0]) {
  891. minkowski() {
  892. db25_plate(th = thin_mint, border = expand);
  893. cylinder(r = minkr, h = thin_mint, $fn = facets);
  894. }
  895. }
  896. }
  897. hull() {
  898. rounded_octagon(thin_mint, radius - 2 * wall);
  899. rotate([0, 0, -22.5]) translate([0, 0, transition - 5.0]) {
  900. minkowski() {
  901. db25_plate(th = thin_mint, border = expand - 2 * wall);
  902. cylinder(r = minkr, h = thin_mint, $fn = facets);
  903. }
  904. }
  905. }
  906. }
  907. // db25 mounting plate
  908. rotate([0, 0, -22.5]) translate([0, 0, transition]) {
  909. difference() {
  910. db25_plate(th = db25_t, border = expand);
  911. db25_cutout(th = db25_t);
  912. }
  913. // connector border
  914. translate([0, 0, -5.0]) difference() {
  915. overhang = 3.0;
  916. minkowski() {
  917. db25_plate(th = 5.0 + db25_t + overhang, border = expand);
  918. cylinder(r = minkr, h = thin_mint, $fn = facets);
  919. }
  920. db25_plate(th = 5.0 + db25_t + overhang + thin_mint, border = expand);
  921. }
  922. }
  923. // for testing
  924. *rotate([0, 0, -22.5]) translate([0, 0, 40]) db25_plate(th = 1.0, border = 1.0);
  925. }
  926. }
  927. module octa_mount_stand(height, lip, transition, radius, top_xradius, top_yradius) {
  928. // flare to db25 connector mounting plate
  929. expand = 3;
  930. // height of connector
  931. guard_height = 9.525;
  932. // thickness of db25 plate
  933. db25_t = 3 * wall;
  934. translate([0, 0, height]) {
  935. minkr = 2.0;
  936. // db25 mounting plate
  937. rotate([0, 0, -22.5]) translate([0, 0, transition]) {
  938. // add guard wall around connector
  939. difference() {
  940. minkowski() {
  941. db25_plate(th = guard_height + db25_t, border = 1.8 * expand);
  942. cylinder(r = minkr, h = thin_mint, $fn = facets);
  943. }
  944. db25_plate(th = guard_height + db25_t + thin_mint, border = 1.8 * expand);
  945. }
  946. }
  947. // ring and connector
  948. translate([0, 0, height]) {
  949. o_rad = 8;
  950. i_rad = 3;
  951. rotate([0, 90, -22.5]) {
  952. // connector
  953. translate([-guard_height, 13, 0]) cube([guard_height, 10, o_rad/2]);
  954. translate([-guard_height, 9, o_rad/4]) rotate([0, 90, 0]) {
  955. difference() {
  956. cylinder(r = o_rad, h = guard_height, $fn = facets);
  957. translate([-10, -16, 0]) cube([20, 20, 10]);
  958. }
  959. }
  960. // ring
  961. translate([-o_rad, 30, 0]) {
  962. shock_mount_ring(o_rad, i_rad, ring_wall);
  963. }
  964. }
  965. }
  966. }
  967. }
  968. // top conical section that plugs into capsule array
  969. module octa_capsule_array_mount(angles) {
  970. difference() {
  971. union() {
  972. difference() {
  973. cylinder(h = mount_top_height, r1 = mount_radius + wall, r2 = mount_radius_capsule + 0.9, $fn = facets);
  974. cylinder(h = mount_top_height, r1 = mount_radius, r2 = mount_radius_capsule - 2 * wall * wall, $fn = facets);
  975. }
  976. // second set of optional "leaves" to get a better mount
  977. *difference() {
  978. cylinder(h = mount_top_height, r1 = mount_radius + wall, r2 = mount_radius_capsule * 0.8, $fn = facets);
  979. cylinder(h = mount_top_height, r1 = mount_radius, r2 = mount_radius_capsule * 0.8 - 1.2 * wall, $fn = facets);
  980. }
  981. }
  982. // indentations that match the four lower capsule holders
  983. // add ridge height adjustment
  984. translate([0, 0, mount_top_height + (mic_radius - capsule_height) + capsule_height * cos(90 - elev_angle) - 2]) {
  985. for (az = angles) {
  986. rotate([0, 180 - elev_angle, az + 45]) {
  987. translate([0, 0, mic_radius - capsule_height]) {
  988. capsule(leg_angles, 0, 1, ridge_wfit, ridge_hfit, 1);
  989. }
  990. }
  991. }
  992. }
  993. // indentations at the top to open up the array a bit
  994. translate([0, 0, mount_top_height + mount_radius_capsule / 8]) {
  995. for (rot = [45, 135, -135, -45]) {
  996. translate([0, 0, 0]) {
  997. rotate([0, 90, rot]) {
  998. scale([0.5, 0.5, 1.3]) linear_extrude(height = mount_radius_capsule, scale = 2.8) {
  999. minkowski() {
  1000. polygon(points = [[0, mount_radius_capsule * 0.2], [0, - mount_radius_capsule * 0.2],
  1001. [mount_radius_capsule, 0]]);
  1002. circle(r = 2.4, $fn = facets);
  1003. }
  1004. }
  1005. }
  1006. }
  1007. }
  1008. }
  1009. }
  1010. }
  1011. //
  1012. // shock mount components
  1013. //
  1014. // shock mount band that attaches snugly to microphone body
  1015. module octa_shock_mount_band(band_height, radius, delta_radius) {
  1016. rotate([0, 0, 22.5]) {
  1017. // inner octagon, hugs the body
  1018. difference() {
  1019. rounded_octagon_wall(band_height, radius + 3 * wall, 2 * wall);
  1020. rotate([0, 0, -22.5 + 90]) translate([-40, -(1.273 * radius)/2, 0]) {
  1021. cube([80, 1.273 * radius, band_height + thin_mint]);
  1022. }
  1023. // space for screw heads
  1024. slot_w = 4.0;
  1025. slot_d = 1.5;
  1026. for (r = [0, 180]) rotate([0, 0, r - 45])
  1027. translate([radius - slot_d/2, -slot_w/2, 0]) cube([slot_d, slot_w, band_height]);
  1028. }
  1029. // the outer octagon
  1030. rounded_octagon_wall(band_height, radius + delta_radius, 2 * wall);
  1031. }
  1032. // joins inner and outer octagons
  1033. for (m = [0, 1]) mirror([m, 0, 0]) {
  1034. translate([radius, -10, 0]) {
  1035. cube([delta_radius - 4 * wall, 20, band_height]);
  1036. }
  1037. }
  1038. }
  1039. // shock mount internal ring
  1040. module octa_shock_mount_internal_ring(height, radius, band_height, corner) {
  1041. delta_radius = pcb_version == 2 ? 7.5 : 6;
  1042. // octagonal band
  1043. octa_shock_mount_band(band_height, radius, delta_radius);
  1044. // 8 columns for mounting rubber bands
  1045. for (r = [0, 90, 180, 270]) rotate([0, 0, r]) {
  1046. for (m = [0, 1]) mirror([m, 0, 0]) {
  1047. translate([radius + (pcb_version == 2 ? 3.5 : 2.25), radius/2 - 2, 0]) {
  1048. rotate([0, 0, 0]) {
  1049. difference() {
  1050. // columns
  1051. union() {
  1052. translate([3, 0, 0]) rotate([0, 0, 45]) scale([1.4, 0.8, 1.0])
  1053. cylinder(r = 3, h = height, $fn = facets);
  1054. }
  1055. // lower slots for rubber bands
  1056. rotate([0, 0, 45]) translate([2.5, radius/2, 2.0]) scale([1.0, 1.0, 2.2]) rotate([90, 0, 0]) {
  1057. cylinder(r = 1.1, h = radius * 2, $fn = facets);
  1058. }
  1059. // upper slots for rubber bands
  1060. rotate([0, 0, 45]) translate([2.5, radius/2, height - 2.0]) scale([1.0, 1.0, 2.2]) rotate([90, 0, 0]) {
  1061. cylinder(r = 1.1, h = radius * 2, $fn = facets);
  1062. }
  1063. }
  1064. }
  1065. }
  1066. }
  1067. // walls between columns so that they cannot bend
  1068. rotate([0, 0, 45]) translate([radius + (pcb_version == 2 ? 2.7 : 2.25) * wall, -14, 0]) {
  1069. cube([wall, 28, height]);
  1070. }
  1071. }
  1072. }
  1073. // shock mount sleeve, slips over microphone body and has hooks for the elastic bands
  1074. module elastic_band_hook (slot_r = 1.1) {
  1075. hook_l = 6.0;
  1076. translate([slot_r, hook_l/2, 0]) {
  1077. rotate([90, 0, 0]) scale([1, 2.2, 1]) cylinder(r = slot_r, h = hook_l, $fn = facets);
  1078. }
  1079. }
  1080. module octa_shock_mount_sleeve(radius, height, hooks = true, logo = true) {
  1081. // gap between body and sleeve
  1082. gap = internal_ring_gap + 0;
  1083. difference() {
  1084. // fit gap for slide tubes
  1085. sgap = 0.2;
  1086. stop_ro = 2.0 + 2 * wall + sgap;
  1087. union() {
  1088. // sleeve
  1089. rotate([0, 0, 22.5]) rounded_octagon_wall(height, radius + 2 * wall + gap, 2 * wall);
  1090. // tubes for stops
  1091. for (r = [0, 90, 180, 270]) {
  1092. rotate([0, 0, r + 45]) {
  1093. translate([radius - 2 * wall + gap, 0, 0]) {
  1094. difference() {
  1095. scale([1, 1.4, 1]) cylinder(r = stop_ro, h = height, $fn = facets);
  1096. translate([-2 * stop_ro, -2 * stop_ro, 0]) {
  1097. cube([2 * stop_ro, 4 * stop_ro, height]);
  1098. }
  1099. }
  1100. }
  1101. }
  1102. }
  1103. // pillars for elastic band hooks
  1104. if (hooks) {
  1105. for (r = [0, 90, 180, 270]) rotate([0, 0, r + 45]) {
  1106. pill_r = 2.5;
  1107. translate([radius + stop_ro + gap - 2 * wall, 0, 0]) {
  1108. difference() {
  1109. scale([2, 1, 1]) cylinder(r = pill_r, h = height, $fn = facets);
  1110. translate([-7 * wall, -pill_r, 0]) cube([6 * wall, pill_r * 2, height]);
  1111. }
  1112. }
  1113. }
  1114. }
  1115. // add ccrma logo
  1116. if (logo) {
  1117. rotate([0, 0, 90]) {
  1118. translate([0, -(radius - (pcb_version == 2 ? gap + 1.4 : 0) + 2 * wall),
  1119. height / 2]) {
  1120. rotate([90, 270, 0]) {
  1121. logo_scale = 1 / (pcb_version == 2 ? 3.0 : 2.4);
  1122. scale([logo_scale, logo_scale, 1.0]) {
  1123. ccrma_logo(1.65);
  1124. }
  1125. }
  1126. }
  1127. }
  1128. }
  1129. }
  1130. // slots for stops and screws
  1131. for (r = [0, 90, 180, 270]) {
  1132. // stops
  1133. stop_r = 2.0 + sgap;
  1134. rotate([0, 0, r + 45]) {
  1135. translate([radius - 2 * wall + gap, 0, 0]) {
  1136. // there is a little bit of play between the wd assembly and the top
  1137. ws_play = 0.4;
  1138. cylinder(r = stop_r, h = height - 10.0 - ws_play, $fn = facets);
  1139. }
  1140. }
  1141. // screws
  1142. screw_h = 1.3;
  1143. rotate([0, 0, r + 22.5]) {
  1144. translate([radius - 1.5 * wall + gap, -3.5/2, 0]) {
  1145. cube([screw_h + sgap, 3.5, height - 8]);
  1146. }
  1147. }
  1148. }
  1149. // slot for front mark
  1150. translate([radius - 2 * wall, 0, 0]) cylinder(r = 1.5, h = height, $fn = facets);
  1151. // shave channel for logo
  1152. translate([radius - 2 * wall, -10/2, 0]) cube([wall/3, 10, height]);
  1153. // upper elastic band hooks
  1154. for (r = [0, 90, 180, 270]) rotate([0, 0, r + 45]) {
  1155. translate([radius + stop_ro + gap - 2*wall, 0, height - 1.6]) {
  1156. elastic_band_hook();
  1157. }
  1158. }
  1159. // lower elastic band hooks
  1160. for (r = [0, 90, 180, 270]) rotate([0, 0, r + 45]) {
  1161. translate([radius + stop_ro + gap - 2*wall, 0, 1.6]) {
  1162. rotate([180, 0, 0]) elastic_band_hook();
  1163. }
  1164. }
  1165. }
  1166. }
  1167. // shock mount external ring
  1168. module octa_shock_mount_external_ring_old(height, radius, corner) {
  1169. // main ring
  1170. rotate([0, 0, 22.5]) rounded_octagon_wall(ring_ext_height, radius, ring_wall);
  1171. for (rot = [0, 90, 180, 270]) {
  1172. // anchors for rubber bands
  1173. rotate([0, 0, rot + 45]) {
  1174. translate([radius * cos(22.5) + ring_wall + 0.75, -6, 0]) {
  1175. minkowski() {
  1176. cube([4 - 2, 12, ring_ext_height]);
  1177. cylinder(r = 1.5, h = thin_mint, $fn = facets);
  1178. }
  1179. }
  1180. translate([radius * cos(22.5), -2, 0]) {
  1181. cube([7, 4, ring_ext_height]);
  1182. }
  1183. }
  1184. }
  1185. // connection to hub
  1186. translate([radius * cos(22.5), -2, 0]) {
  1187. cube([10, 4, ring_ext_height * 2]);
  1188. }
  1189. // reinforce connection to ring
  1190. intersection() {
  1191. translate([radius * cos(22.5), 0, 0]) {
  1192. difference() {
  1193. cylinder(r = 6, h = ring_ext_height * 2, $fn = 4);
  1194. translate([-10, -5, 0]) {
  1195. cube([10, 10, ring_ext_height * 2]);
  1196. }
  1197. }
  1198. }
  1199. translate([radius + ring_wall - 7, 0, 0]) {
  1200. rotate([0, 0, 45]) cylinder(r1 = radius * 1.5, r2 = ring_wall/2 + 1, h = ring_ext_height * 2, $fn = 4);
  1201. }
  1202. }
  1203. // reinforcement
  1204. intersection() {
  1205. rotate([0, 0, 22.5]) rounded_octagon_wall(ring_ext_height * 2, radius, ring_wall);
  1206. translate([radius - 6.5, 0, 0]) {
  1207. rotate([0, 0, 45]) cylinder(r1 = radius * 1.5, r2 = ring_wall/2 + 1, h = ring_ext_height * 2, $fn = 4);
  1208. }
  1209. }
  1210. // rotating mount
  1211. o_rad = 8;
  1212. i_rad = 3;
  1213. rotate([0, 90, -90]) {
  1214. translate([-o_rad, radius * cos(22.5) + o_rad + ring_wall * 2, -2]) {
  1215. shock_mount_ring(o_rad, i_rad, ring_wall);
  1216. }
  1217. }
  1218. }
  1219. module octa_shock_mount_external_ring(height, radius, corner) {
  1220. // main ring
  1221. rotate([0, 0, 22.5]) rounded_octagon_wall(ring_ext_height, radius, ring_wall);
  1222. for (m = [0, 1]) mirror([0, m, 0]) {
  1223. for (rot = [0, 90, 180, 270]) {
  1224. // anchors for rubber bands
  1225. rotate([0, 0, rot + 20]) {
  1226. translate([radius * cos(22.5) + ring_wall + 2.0, -5, 0]) {
  1227. minkowski() {
  1228. cube([4 - 3, 6, ring_ext_height]);
  1229. cylinder(r = 1.0, h = thin_mint, $fn = facets);
  1230. }
  1231. }
  1232. translate([radius * cos(22.5), -2, 0]) {
  1233. cube([7, 4, ring_ext_height]);
  1234. }
  1235. }
  1236. }
  1237. }
  1238. // connection to hub
  1239. translate([radius * cos(22.5), -2, 0]) {
  1240. cube([10, 4, ring_ext_height * 2]);
  1241. }
  1242. // reinforce connection to ring
  1243. intersection() {
  1244. translate([radius * cos(22.5), 0, 0]) {
  1245. difference() {
  1246. cylinder(r = 6, h = ring_ext_height * 2, $fn = 4);
  1247. translate([-10, -5, 0]) {
  1248. cube([10, 10, ring_ext_height * 2]);
  1249. }
  1250. }
  1251. }
  1252. translate([radius + ring_wall - 7, 0, 0]) {
  1253. rotate([0, 0, 45]) cylinder(r1 = radius * 1.5, r2 = ring_wall/2 + 1, h = ring_ext_height * 2, $fn = 4);
  1254. }
  1255. }
  1256. // reinforcement
  1257. intersection() {
  1258. rotate([0, 0, 22.5]) rounded_octagon_wall(ring_ext_height * 2, radius, ring_wall);
  1259. translate([radius - 6.5, 0, 0]) {
  1260. rotate([0, 0, 45]) cylinder(r1 = radius * 1.5, r2 = ring_wall/2 + 1, h = ring_ext_height * 2, $fn = 4);
  1261. }
  1262. }
  1263. // rotating mount
  1264. o_rad = 8;
  1265. i_rad = 3;
  1266. rotate([0, 90, -90]) {
  1267. translate([-o_rad, radius * cos(22.5) + o_rad + ring_wall * 2, -2]) {
  1268. shock_mount_ring(o_rad, i_rad, ring_wall);
  1269. }
  1270. }
  1271. }
  1272. // stand mount with quick clip connector
  1273. module octa_quik_release_stand_mount(band_height, radius) {
  1274. vertical_offset = 18;
  1275. mount_offset = 3.0;
  1276. // octagonal band
  1277. octa_shock_mount_band(band_height, radius, pcb_version == 2 ? 7.5 : 6);
  1278. difference() {
  1279. hull() {
  1280. // attachment "plate"
  1281. translate([radius, -10, 0]) {
  1282. cube([2, 20, band_height]);
  1283. }
  1284. // quik release adapter tube
  1285. translate([(radius + mic_mount_radius + mic_mount_wall + 6.0 + mount_offset) * cos(22.5), 0,
  1286. vertical_offset]) {
  1287. cylinder(r = mic_mount_radius + mic_mount_fit + mic_mount_wall, h = band_height - vertical_offset, $fn = facets);
  1288. }
  1289. }
  1290. // cutout for the center hole and side hole of the adapter
  1291. translate([(radius + mic_mount_radius + mic_mount_wall + 6.0 + mount_offset) * cos(22.5), 0,
  1292. vertical_offset + thin_mint]) {
  1293. cylinder(r = mic_mount_radius + mic_mount_fit, h = mic_mount_height, $fn = facets);
  1294. }
  1295. }
  1296. translate([(radius + mic_mount_radius + mic_mount_wall + 6.0 + mount_offset) * cos(22.5), 0,
  1297. mic_mount_height + vertical_offset + thin_mint]) {
  1298. rotate([0, 180, 180]) quik_release_stand_adapter(mic_mount_height, mount_wall, mic_mount_wall);
  1299. }
  1300. }
  1301. // octathingy arm mount for robotic arm
  1302. module octa_arm_mount(band_height, radius, height) {
  1303. vertical_offset = 18;
  1304. mount_offset = 3.0;
  1305. // octagonal band
  1306. octa_shock_mount_band(band_height, radius, pcb_version == 2 ? 7.5 : 6);
  1307. // pillars for arm grips
  1308. sphear_arm_mount_pillars(radius, height - 50.0, grip_sep, grip_width);
  1309. }
  1310. module octa_arm_mount_pillars(band_height, radius, height, grip_width, grip_depth) {
  1311. vertical_offset = 18;
  1312. mount_offset = 3.0;
  1313. // pillars for arm grips
  1314. sphear_arm_mount_pillars(radius, height - 60.0, grip_sep, grip_width, grip_depth);
  1315. }
  1316. ////
  1317. //// render all the different parts
  1318. ////
  1319. // microphone body: stalk from capsule flare to capsule array (for microphone version 1)
  1320. //
  1321. module render_octa_capsule_stalk(z_offset) {
  1322. translate([0, 0, z_offset]) {
  1323. octa_mount_stalk(pcb_hi_clear + pcb_hi_exp, mount_lip, flare_height, octa_pcb_radius, mount_radius + wall, stalk_height, 1);
  1324. translate([0, 0, pcb_hi_clear + pcb_hi_exp + flare_height + stalk_height]) {
  1325. octa_capsule_array_mount([45, 135, -45, -135]);
  1326. }
  1327. }
  1328. }
  1329. // microphone body: flare to capsule array (slips into PCB holder body)
  1330. //
  1331. module render_octa_capsule_flare(z_offset) {
  1332. translate([0, 0, z_offset]) {
  1333. octa_mount_flare(pcb_hi_clear + pcb_hi_exp, mount_lip, flare_height, octa_pcb_radius, mount_radius + wall, stalk_height, 1);
  1334. }
  1335. }
  1336. // microphone body: main body, holds printed circuit boards
  1337. //
  1338. module render_octa_pcb_mount(z_offset, showint) {
  1339. translate([0, 0, z_offset]) {
  1340. octa_mount_body(octa_pcb_mount_height, octa_pcb_radius, mount_lip, mount_lip, 0);
  1341. // add ccrma logo
  1342. rotate([0, 0, -90 + 22.5]) {
  1343. translate([0, -(octa_pcb_radius - (pcb_version == 2 ? 3.4 : 3.7)), octa_pcb_mount_height / 2]) {
  1344. rotate([90, 270, 0]) {
  1345. logo_scale = 1 / (pcb_version == 2 ? 3.0 : 2.4);
  1346. scale([logo_scale, logo_scale, 1.0]) {
  1347. ccrma_logo(1.65);
  1348. }
  1349. }
  1350. }
  1351. }
  1352. }
  1353. }
  1354. // microphone body: flare to microphone cable (slips into PCB holder body)
  1355. //
  1356. module render_octa_cable_flare(z_offset, flip) {
  1357. translate([0, 0, z_offset]) {
  1358. octa_mount_flare_dual(pcb_low_clear + pcb_low_exp, mount_lip, 20, box_radius + wall, box_radius * 2 - wall,
  1359. mount_corner, cable_diam / 2 + wall, 10, 0);
  1360. }
  1361. }
  1362. // microphone body: flare to dual cable connectors (slips into PCB holder body)
  1363. //
  1364. module render_octa_connector_flare(z_offset, flip) {
  1365. conn_offset = 2.0;
  1366. conn_wall = conn_core_o_diam / 2 - conn_core_diam / 2;
  1367. translate([0, 0, z_offset]) {
  1368. difference() {
  1369. union() {
  1370. octa_mount_flare_connector(pcb_low_clear + pcb_low_exp, mount_lip, 20,
  1371. octa_pcb_radius,
  1372. conn_core_o_diam / 2, conn_core_o_diam + conn_offset);
  1373. for (m = [0, 1]) mirror([0, m, 0]) translate([0, conn_core_o_diam / 2 + conn_offset, pcb_low_clear + pcb_low_exp + 20]) {
  1374. // add two connectors
  1375. rotate([0, 0, -90]) {
  1376. tetra_mount_connector_holder(conn_core_sleeve, conn_core_o_diam / 2, conn_core_diam / 2,
  1377. conn_core_overlap, conn_core_s_diam / 2);
  1378. }
  1379. // add wall in between the two connectors
  1380. translate([- 2 * wall, - (conn_core_o_diam / 2 + conn_offset), 0]) {
  1381. cube([4 * wall, conn_offset + wall, 10]);
  1382. }
  1383. }
  1384. }
  1385. // redo the hole in the connector holder so that it drills into the top of the flare
  1386. for (m = [0, 1]) mirror([0, m, 0]) translate([0, conn_core_o_diam / 2 + conn_offset, 0]) {
  1387. cylinder(r = conn_core_diam / 2, h = 100, $fn = facets);
  1388. }
  1389. }
  1390. }
  1391. }
  1392. // microphone body: flare to db25 connector (slips into PCB holder body)
  1393. //
  1394. module render_octa_mount_dsub_flare(z_offset, flip) {
  1395. updown = 0;
  1396. if (flip) {
  1397. updown = 180;
  1398. }
  1399. rotate([0, updown, 90]) {
  1400. conn_offset = 2.0;
  1401. translate([0, 0, z_offset - mount_lip]) {
  1402. octa_mount_flare_dsub(pcb_low_clear + pcb_low_exp - (pcb_version == 2 ? 13 : 0), mount_lip,
  1403. pcb_version == 2 ? 33 : 20, octa_pcb_radius,
  1404. conn_core_o_diam / 2, conn_core_o_diam + conn_offset);
  1405. }
  1406. }
  1407. }
  1408. // microphone body: render all parts with a vertical separation
  1409. //
  1410. module render_octa_body(z_offset, spread, showint) {
  1411. rotate([0, 180, 0]) {
  1412. render_octa_mount_dsub_flare(pcb_version == 2 ? 10 : 0, 0);
  1413. }
  1414. lippy = spread - mount_lip;
  1415. render_octa_pcb_mount(lippy, showint);
  1416. render_octa_capsule_flare(octa_pcb_mount_height + 2 * lippy);
  1417. }
  1418. // microphone: render the full assembly with vertical separation between components
  1419. //
  1420. module render_octa_microphone(z_offset, spread) {
  1421. render_octa_body(z_offset, spread);
  1422. lippy = spread - mount_lip;
  1423. render_octa_capsule_array(z_offset + octa_pcb_mount_height + mount_top_height +
  1424. flare_height + stalk_height + pcb_hi_clear + pcb_hi_exp + 2 * lippy + spread + mic_radius);
  1425. render_octa_capsule_stalk(z_offset + (pcb_version == 2 ? 43.2 : 49.2) - 10.0);
  1426. }
  1427. // microphone: render the full assembly with vertical separation between components
  1428. // cut out half of the assembly so that we can see the inside
  1429. //
  1430. module render_octa_microphone_cutout(z_offset, spread) {
  1431. difference() {
  1432. render_octa_microphone(z_offset, spread);
  1433. // a cube that blots out 1/4 of the microphone
  1434. rotate([0, 0, 90]) {
  1435. translate([0, 0, -50]) {
  1436. cube([50, 100, 650]);
  1437. }
  1438. }
  1439. }
  1440. }
  1441. // shock mount: microphone clip on stand mount
  1442. //
  1443. module render_octa_shock_mount_stand(z_offset) {
  1444. translate([z_offset]) {
  1445. shock_mount_stand(mic_mount_height, mount_wall, mic_mount_wall);
  1446. }
  1447. }
  1448. // shock mount: external ring
  1449. //
  1450. module render_octa_shock_mount_external_ring_old(z_offset) {
  1451. translate([0, 0, z_offset]) {
  1452. shock_mount_external_ring(external_ring_height, box_radius + wall, box_radius * 2 - wall, mount_corner, main_radius_inc, 0);
  1453. }
  1454. }
  1455. module render_octa_shock_mount_external_ring(z_offset) {
  1456. translate([0, 0, z_offset]) {
  1457. octa_shock_mount_external_ring(external_ring_height, octa_pcb_radius + internal_ring_gap + main_radius_inc + 5.25, 20);
  1458. }
  1459. }
  1460. // shock mount: bottom internal ring
  1461. //
  1462. module render_octa_shock_mount_internal_ring_bot(z_offset) {
  1463. translate([0, 0, z_offset]) {
  1464. shock_mount_internal_ring(external_ring_height, box_radius + wall, box_radius * 2 - wall, mount_corner, internal_ring_gap, 1);
  1465. }
  1466. }
  1467. module render_octa_shock_mount_internal_ring_bot(z_offset) {
  1468. translate([0, 0, z_offset]) {
  1469. shock_mount_internal_ring(external_ring_height, A/2 + wall, A/2 + 3, octa_pcb_radius * 2/3, internal_ring_gap, 1);
  1470. }
  1471. }
  1472. // shock mount: top internal ring
  1473. //
  1474. module render_octa_shock_mount_internal_ring_top_old(z_offset) {
  1475. translate([0, 0, z_offset]) {
  1476. shock_mount_internal_ring(external_ring_height, box_radius + wall, box_radius * 2 - wall, mount_corner, internal_ring_gap, 0);
  1477. }
  1478. }
  1479. module render_octa_shock_mount_internal_ring_top(z_offset) {
  1480. translate([0, 0, z_offset]) {
  1481. shock_mount_internal_ring(external_ring_height, A/2 + wall, A/2 + 3, octa_pcb_radius * 2/3, internal_ring_gap, 0);
  1482. }
  1483. }
  1484. // shock mount: all four internal ring connectors
  1485. //
  1486. module render_octa_shock_mount_ring_connectors(offset) {
  1487. for (o = [0, 1, 2, 3]) {
  1488. translate([-18, (10 + offset) * o, 0]) {
  1489. shock_mount_connector(internal_ring_height, 4, connector_w, connector_d, 0.1);
  1490. }
  1491. }
  1492. }
  1493. // shock mount: render all parts
  1494. //
  1495. module render_octa_shock_mount(z_offset) {
  1496. // internal rings
  1497. translate([0, 0, z_offset + internal_ring_height / 2]) {
  1498. render_octa_shock_mount_internal_ring_top(0);
  1499. rotate([0, 180, 0]) {
  1500. render_octa_shock_mount_internal_ring_bot(internal_ring_height + 2);
  1501. }
  1502. // insert the connecting rods
  1503. for (r = [0, 90, 180, 270]) {
  1504. rotate([0, 0, r]) {
  1505. translate([((r % 180) ? box_radius * 2 : box_radius) + 3 * wall + internal_ring_gap, 0, -1]) {
  1506. rotate([0, 90, 0]) {
  1507. translate([-4, -5, 1]) {
  1508. shock_mount_connector(internal_ring_height, 4, connector_w, connector_d, 0.1);
  1509. }
  1510. }
  1511. }
  1512. }
  1513. }
  1514. }
  1515. // external ring
  1516. translate([0, 0, z_offset - external_ring_height / 4]) {
  1517. render_octa_shock_mount_external_ring(0);
  1518. }
  1519. // mount to stand
  1520. translate([box_radius + mount_corner + ring_wall + ring_arm_gap + 8 + ring_wall / 2 + 4, 0, -(mic_mount_height + mic_mount_radius + external_ring_height / 4)]) {
  1521. render_octa_shock_mount_stand(0);
  1522. }
  1523. }