add sma_rigid

This commit is contained in:
Pierre Lecomte 2023-05-04 14:57:04 +02:00
parent e7b05ca05b
commit a83fcd74c8
2 changed files with 634 additions and 0 deletions

203
cad/sma_rigid.scad Normal file
View File

@ -0,0 +1,203 @@
include <threads.scad>;
// Resolution of outter surface (360 for 3D printing)
res = 32;
/*[ Array parameters ]*/
// sphere radius (mm):
r = 60;
// shell thickness (mm):
e = 6;
// microphones zenith coordinates (°):
theta = [0, 90, 90, 90, 90, 180, 54.7356, 54.7356, 54.7356, 54.7356, 125.264, 125.264, 125.264, 125.264];
// microphone azimuth coordinates (°):
phi = [0, 0, 90, 180, 270, 0, 45, 135, 225, 315, 45, 135, 225, 315];
/* the microphone array can be rotated to be in accordance with the array cut and mic stand position
*/
// microphones global rotation (°):
mics_rotate = [-90, 0, 0];
/*[ Cut parameters ]*/
// minimal zenith angle for the cut (°):
angle_min = 75;
// maximal zenith angle for the cut (°):
angle_max = 82;
// screws diameter, metric (mm):
d_screw = 3;
// screws number
n_screw = 4;
// screws azimuth angle offset (°):
screw_phi_offset = 0;
/*[ Mounting holes parameters ]*/
/*
The hole for passing the microphone cables is centered on the sphere cut. This eases the cable mounting and allows reducing the hole diameter because the mics plugs don't have to pass through the hole when assembling the SMA.
To optimize the hole diameter see here : http://hydra.nat.uni-magdeburg.de/packing/cci/cci.html#overview
*/
// azimuth offset for the cable hole (°):
hole_phi_offset = 45;
// hole diameter (mm):
d_hole = 10;
/*
The mic stand threaded hole should be close to the passing cable hole. It's direction is set as an offset from the cable hole direction.abs
*/
// threaded hole offset from cable hole [theta(°), phi(°)]:
dir_thread = [13, 0];
// Hollow sphere
module hollow(r1=r-e, r2=r, fn1=$fn, fn2=$fn){
difference(){
sphere(r=r2, $fn=fn1);
sphere(r=r1, $fn=fn2);
}
}
// Torus for "joint torique" for B&K 1/4" mics
module b_k(){
mirror([0,0,-1])
rotate_extrude($fn=32){
square([10.5/2,10]);
translate([10.6/2-1, 0])
circle(r=1,$fn=32);
translate([0,-1.1*e])
square([3.55, 1.1*e]);
}
}
echo(len(theta));
module mics(){
rotate(mics_rotate)
for (i = [0 : len(theta)-1]){
rotate([theta[i], 0, phi[i]])
translate([0, 0, r-e+1]){
b_k();
translate([3,3,e-1.8])
linear_extrude(3)
text(str(i+1), size=3);
}
}
}
module bottom_shell(r1= r-e, r2=r-e/2, r3=r, delta=0.2) {
union(){
difference(){
hollow(r1, r2-delta/2, fn1=24, fn2=24);
translate([0, 0, r2 * sin(90 - angle_min)-delta])
cylinder(r=1.1*r2, h=2*r);
}
difference(){
hollow(r1, r3, fn2=24, fn1=res);
translate([0, 0, r3 * sin(90 - angle_max)])
cylinder(r=1.1*r3, h=2*r);
}
}
}
module top_shell(r1= r-e, r2=r-e/2, r3=r, delta=0) {
union(){
difference(){
hollow(r1, r2+0.1, fn1=24, fn2=24);
translate([0, 0, -2*r+r2 * sin(90 - angle_min)])
cylinder(r=1.1*r2, h=2*r);
}
difference(){
hollow(r2, r3, fn1=res, fn2=24);
translate([0, 0, -2*r+r3 * sin(90 - angle_max)])
cylinder(r=1.1*r3, h=2*r);
}
}
}
module vis(d = d_screw, $fn=72) {
union(){
cylinder(d=d+0.2,h=e);
// param = [nut thickness, nut diameter, screw_head thikness]
param = d == 2 ? [1.6, 4.6, 1.2] : // M2
d == 2.5 ? [2, 5.8, 1.5] : // M2.5
d == 3 ? [2.4, 6.4, 1.7] : // M3
d == 4 ? [3.2, 8.1, 2.3] : // M4
d == 5 ? [4, 9.2, 2.8] : // M5
d == 6 ? [5, 11.5, 3.3] : false; // M6
translate([0,0,e-param[2]-0.2]){
cylinder(d1=d,d2=2*d,h=param[2]);
translate([0, 0, param[2]])
cylinder(d=2*d, h=1);
}
translate([0,0,-e/2])
cylinder(d=param[1]+0.2, h=param[0]+1, $fn=6);
}
}
module attach() {
rotate([(angle_min+angle_max)/2,0,hole_phi_offset])
cylinder(d=d_hole, h=100);
rotate([(angle_min+angle_max)/2 + dir_thread[0],0, hole_phi_offset + dir_thread[1]])
translate([0,0,(r-3*e)])
render()
//english_thread(3/8,16,3.5*e/25.4,internal=true);
metric_thread (diameter=6, pitch=1, length=20);
}
module vis_all(){
for (i = [0 : n_screw-1]){
rotate([(angle_min+angle_max)/2, 0, i*90+screw_phi_offset])
translate([0,0,r-e])
vis();
}
}
module bottom_shell_all(){
difference(){
bottom_shell();
attach();
vis_all();
mics();
}
}
module top_shell_all(){
difference(){
top_shell();
attach();
mics();
vis_all();
}
}
module test_vis(){
difference(){
translate([0,0,e/2])
cube([11, 11, e], center=true);
vis();
}
}
module test_mic(){
difference(){
translate([0, 0, -e/2])
cube([13, 13, e], center=true);
union(){
cylinder(r=3.55,h=2*e, center= true);
translate([0, 0, -1])
torus();
}
}
}
//top_shell_all();
bottom_shell_all();

431
cad/threads.scad Normal file
View File

@ -0,0 +1,431 @@
/*
* ISO-standard metric threads, following this specification:
* http://en.wikipedia.org/wiki/ISO_metric_screw_thread
*
* Copyright 2022 Dan Kirshner - dan_kirshner@yahoo.com
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See <http://www.gnu.org/licenses/>.
*
* Version 2.7. 2022-02-27 Increase minimum thread segments.
* Version 2.6. 2021-05-16 Contributed patches for leadin (thanks,
jeffery.spirko@tamucc.edu) and aligning thread
"facets" (triangulation) with base cylinder
(thanks, rambetter@protonmail.com).
* Version 2.5. 2020-04-11 Leadin option works for internal threads.
* Version 2.4. 2019-07-14 Add test option - do not render threads.
* Version 2.3. 2017-08-31 Default for leadin: 0 (best for internal threads).
* Version 2.2. 2017-01-01 Correction for angle; leadfac option. (Thanks to
* Andrew Allen <a2intl@gmail.com>.)
* Version 2.1. 2016-12-04 Chamfer bottom end (low-z); leadin option.
* Version 2.0. 2016-11-05 Backwards compatibility (earlier OpenSCAD) fixes.
* Version 1.9. 2016-07-03 Option: tapered.
* Version 1.8. 2016-01-08 Option: (non-standard) angle.
* Version 1.7. 2015-11-28 Larger x-increment - for small-diameters.
* Version 1.6. 2015-09-01 Options: square threads, rectangular threads.
* Version 1.5. 2015-06-12 Options: thread_size, groove.
* Version 1.4. 2014-10-17 Use "faces" instead of "triangles" for polyhedron
* Version 1.3. 2013-12-01 Correct loop over turns -- don't have early cut-off
* Version 1.2. 2012-09-09 Use discrete polyhedra rather than linear_extrude ()
* Version 1.1. 2012-09-07 Corrected to right-hand threads!
*/
// Examples.
//
// Standard M8 x 1.
// metric_thread (diameter=8, pitch=1, length=4);
// Square thread.
// metric_thread (diameter=8, pitch=1, length=4, square=true);
// Non-standard: long pitch, same thread size.
//metric_thread (diameter=8, pitch=4, length=4, thread_size=1, groove=true);
// Non-standard: 20 mm diameter, long pitch, square "trough" width 3 mm,
// depth 1 mm.
//metric_thread (diameter=20, pitch=8, length=16, square=true, thread_size=6,
// groove=true, rectangle=0.333);
// English: 1/4 x 20.
//english_thread (diameter=1/4, threads_per_inch=20, length=1);
// Tapered. Example -- pipe size 3/4" -- per:
// http://www.engineeringtoolbox.com/npt-national-pipe-taper-threads-d_750.html
// english_thread (diameter=1.05, threads_per_inch=14, length=3/4, taper=1/16);
// Thread for mounting on Rohloff hub.
//difference () {
// cylinder (r=20, h=10, $fn=100);
//
// metric_thread (diameter=34, pitch=1, length=10, internal=true, n_starts=6);
//}
// ----------------------------------------------------------------------------
function segments (diameter) = min (150, max (ceil (diameter*6), 25));
// ----------------------------------------------------------------------------
// diameter - outside diameter of threads in mm. Default: 8.
// pitch - thread axial "travel" per turn in mm. Default: 1.
// length - overall axial length of thread in mm. Default: 1.
// internal - true = clearances for internal thread (e.g., a nut).
// false = clearances for external thread (e.g., a bolt).
// (Internal threads should be "cut out" from a solid using
// difference ()). Default: false.
// n_starts - Number of thread starts (e.g., DNA, a "double helix," has
// n_starts=2). See wikipedia Screw_thread. Default: 1.
// thread_size - (non-standard) axial width of a single thread "V" - independent
// of pitch. Default: same as pitch.
// groove - (non-standard) true = subtract inverted "V" from cylinder
// (rather thanadd protruding "V" to cylinder). Default: false.
// square - true = square threads (per
// https://en.wikipedia.org/wiki/Square_thread_form). Default:
// false.
// rectangle - (non-standard) "Rectangular" thread - ratio depth/(axial) width
// Default: 0 (standard "v" thread).
// angle - (non-standard) angle (deg) of thread side from perpendicular to
// axis (default = standard = 30 degrees).
// taper - diameter change per length (National Pipe Thread/ANSI B1.20.1
// is 1" diameter per 16" length). Taper decreases from 'diameter'
// as z increases. Default: 0 (no taper).
// leadin - 0 (default): no chamfer; 1: chamfer (45 degree) at max-z end;
// 2: chamfer at both ends, 3: chamfer at z=0 end.
// leadfac - scale of leadin chamfer length (default: 1.0 = 1/2 thread).
// test - true = do not render threads (just draw "blank" cylinder).
// Default: false (draw threads).
module metric_thread (diameter=8, pitch=1, length=1, internal=false, n_starts=1,
thread_size=-1, groove=false, square=false, rectangle=0,
angle=30, taper=0, leadin=0, leadfac=1.0, test=false)
{
// thread_size: size of thread "V" different than travel per turn (pitch).
// Default: same as pitch.
local_thread_size = thread_size == -1 ? pitch : thread_size;
local_rectangle = rectangle ? rectangle : 1;
n_segments = segments (diameter);
h = (test && ! internal) ? 0 : (square || rectangle) ? local_thread_size*local_rectangle/2 : local_thread_size / (2 * tan(angle));
h_fac1 = (square || rectangle) ? 0.90 : 0.625;
// External thread includes additional relief.
h_fac2 = (square || rectangle) ? 0.95 : 5.3/8;
tapered_diameter = diameter - length*taper;
difference () {
union () {
if (! groove) {
if (! test) {
metric_thread_turns (diameter, pitch, length, internal, n_starts,
local_thread_size, groove, square, rectangle, angle,
taper);
}
}
difference () {
// Solid center, including Dmin truncation.
if (groove) {
cylinder (r1=diameter/2, r2=tapered_diameter/2,
h=length, $fn=n_segments);
} else if (internal) {
cylinder (r1=diameter/2 - h*h_fac1, r2=tapered_diameter/2 - h*h_fac1,
h=length, $fn=n_segments);
} else {
// External thread.
cylinder (r1=diameter/2 - h*h_fac2, r2=tapered_diameter/2 - h*h_fac2,
h=length, $fn=n_segments);
}
if (groove) {
if (! test) {
metric_thread_turns (diameter, pitch, length, internal, n_starts,
local_thread_size, groove, square, rectangle,
angle, taper);
}
}
}
// Internal thread lead-in: take away from external solid.
if (internal) {
// "Negative chamfer" z=0 end if leadin is 2 or 3.
if (leadin == 2 || leadin == 3) {
// Fixes by jeffery.spirko@tamucc.edu.
cylinder (r1=diameter/2 - h + h*h_fac1*leadfac,
r2=diameter/2 - h,
h=h*h_fac1*leadfac, $fn=n_segments);
/*
cylinder (r1=diameter/2,
r2=diameter/2 - h*h_fac1*leadfac,
h=h*h_fac1*leadfac, $fn=n_segments);
*/
}
// "Negative chamfer" z-max end if leadin is 1 or 2.
if (leadin == 1 || leadin == 2) {
translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) {
cylinder (r1=tapered_diameter/2 - h,
h=h*h_fac1*leadfac,
r2=tapered_diameter/2 - h + h*h_fac1*leadfac,
$fn=n_segments);
/*
cylinder (r1=tapered_diameter/2 - h*h_fac1*leadfac,
h=h*h_fac1*leadfac,
r2=tapered_diameter/2,
$fn=n_segments);
*/
}
}
}
}
if (! internal) {
// Chamfer z=0 end if leadin is 2 or 3.
if (leadin == 2 || leadin == 3) {
difference () {
cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
cylinder (r2=diameter/2, r1=diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
$fn=n_segments);
}
}
// Chamfer z-max end if leadin is 1 or 2.
if (leadin == 1 || leadin == 2) {
translate ([0, 0, length + 0.05 - h*h_fac1*leadfac]) {
difference () {
cylinder (r=diameter/2 + 1, h=h*h_fac1*leadfac, $fn=n_segments);
cylinder (r1=tapered_diameter/2, r2=tapered_diameter/2 - h*h_fac1*leadfac, h=h*h_fac1*leadfac,
$fn=n_segments);
}
}
}
}
}
}
// ----------------------------------------------------------------------------
// Input units in inches.
// Note: units of measure in drawing are mm!
module english_thread (diameter=0.25, threads_per_inch=20, length=1,
internal=false, n_starts=1, thread_size=-1, groove=false,
square=false, rectangle=0, angle=30, taper=0, leadin=0,
leadfac=1.0, test=false)
{
// Convert to mm.
mm_diameter = diameter*25.4;
mm_pitch = (1.0/threads_per_inch)*25.4;
mm_length = length*25.4;
echo (str ("mm_diameter: ", mm_diameter));
echo (str ("mm_pitch: ", mm_pitch));
echo (str ("mm_length: ", mm_length));
metric_thread (mm_diameter, mm_pitch, mm_length, internal, n_starts,
thread_size, groove, square, rectangle, angle, taper, leadin,
leadfac, test);
}
// ----------------------------------------------------------------------------
module metric_thread_turns (diameter, pitch, length, internal, n_starts,
thread_size, groove, square, rectangle, angle,
taper)
{
// Number of turns needed.
n_turns = floor (length/pitch);
intersection () {
// Start one below z = 0. Gives an extra turn at each end.
for (i=[-1*n_starts : n_turns+1]) {
translate ([0, 0, i*pitch]) {
metric_thread_turn (diameter, pitch, internal, n_starts,
thread_size, groove, square, rectangle, angle,
taper, i*pitch);
}
}
// Cut to length.
translate ([0, 0, length/2]) {
cube ([diameter*3, diameter*3, length], center=true);
}
}
}
// ----------------------------------------------------------------------------
module metric_thread_turn (diameter, pitch, internal, n_starts, thread_size,
groove, square, rectangle, angle, taper, z)
{
n_segments = segments (diameter);
fraction_circle = 1.0/n_segments;
for (i=[0 : n_segments-1]) {
// Keep polyhedron "facets" aligned -- circumferentially -- with base
// cylinder facets. (Patch contributed by rambetter@protonmail.com.)
rotate ([0, 0, (i + 0.5)*360*fraction_circle + 90]) {
translate ([0, 0, i*n_starts*pitch*fraction_circle]) {
//current_diameter = diameter - taper*(z + i*n_starts*pitch*fraction_circle);
thread_polyhedron ((diameter - taper*(z + i*n_starts*pitch*fraction_circle))/2,
pitch, internal, n_starts, thread_size, groove,
square, rectangle, angle);
}
}
}
}
// ----------------------------------------------------------------------------
module thread_polyhedron (radius, pitch, internal, n_starts, thread_size,
groove, square, rectangle, angle)
{
n_segments = segments (radius*2);
fraction_circle = 1.0/n_segments;
local_rectangle = rectangle ? rectangle : 1;
h = (square || rectangle) ? thread_size*local_rectangle/2 : thread_size / (2 * tan(angle));
outer_r = radius + (internal ? h/20 : 0); // Adds internal relief.
//echo (str ("outer_r: ", outer_r));
// A little extra on square thread -- make sure overlaps cylinder.
h_fac1 = (square || rectangle) ? 1.1 : 0.875;
inner_r = radius - h*h_fac1; // Does NOT do Dmin_truncation - do later with
// cylinder.
translate_y = groove ? outer_r + inner_r : 0;
reflect_x = groove ? 1 : 0;
// Make these just slightly bigger (keep in proportion) so polyhedra will
// overlap.
x_incr_outer = (! groove ? outer_r : inner_r) * fraction_circle * 2 * PI * 1.02;
x_incr_inner = (! groove ? inner_r : outer_r) * fraction_circle * 2 * PI * 1.02;
z_incr = n_starts * pitch * fraction_circle * 1.005;
/*
(angles x0 and x3 inner are actually 60 deg)
/\ (x2_inner, z2_inner) [2]
/ \
(x3_inner, z3_inner) / \
[3] \ \
|\ \ (x2_outer, z2_outer) [6]
| \ /
| \ /|
z |[7]\/ / (x1_outer, z1_outer) [5]
| | | /
| x | |/
| / | / (x0_outer, z0_outer) [4]
| / | / (behind: (x1_inner, z1_inner) [1]
|/ | /
y________| |/
(r) / (x0_inner, z0_inner) [0]
*/
x1_outer = outer_r * fraction_circle * 2 * PI;
z0_outer = (outer_r - inner_r) * tan(angle);
//echo (str ("z0_outer: ", z0_outer));
//polygon ([[inner_r, 0], [outer_r, z0_outer],
// [outer_r, 0.5*pitch], [inner_r, 0.5*pitch]]);
z1_outer = z0_outer + z_incr;
// Give internal square threads some clearance in the z direction, too.
bottom = internal ? 0.235 : 0.25;
top = internal ? 0.765 : 0.75;
translate ([0, translate_y, 0]) {
mirror ([reflect_x, 0, 0]) {
if (square || rectangle) {
// Rule for face ordering: look at polyhedron from outside: points must
// be in clockwise order.
polyhedron (
points = [
[-x_incr_inner/2, -inner_r, bottom*thread_size], // [0]
[x_incr_inner/2, -inner_r, bottom*thread_size + z_incr], // [1]
[x_incr_inner/2, -inner_r, top*thread_size + z_incr], // [2]
[-x_incr_inner/2, -inner_r, top*thread_size], // [3]
[-x_incr_outer/2, -outer_r, bottom*thread_size], // [4]
[x_incr_outer/2, -outer_r, bottom*thread_size + z_incr], // [5]
[x_incr_outer/2, -outer_r, top*thread_size + z_incr], // [6]
[-x_incr_outer/2, -outer_r, top*thread_size] // [7]
],
faces = [
[0, 3, 7, 4], // This-side trapezoid
[1, 5, 6, 2], // Back-side trapezoid
[0, 1, 2, 3], // Inner rectangle
[4, 7, 6, 5], // Outer rectangle
// These are not planar, so do with separate triangles.
[7, 2, 6], // Upper rectangle, bottom
[7, 3, 2], // Upper rectangle, top
[0, 5, 1], // Lower rectangle, bottom
[0, 4, 5] // Lower rectangle, top
]
);
} else {
// Rule for face ordering: look at polyhedron from outside: points must
// be in clockwise order.
polyhedron (
points = [
[-x_incr_inner/2, -inner_r, 0], // [0]
[x_incr_inner/2, -inner_r, z_incr], // [1]
[x_incr_inner/2, -inner_r, thread_size + z_incr], // [2]
[-x_incr_inner/2, -inner_r, thread_size], // [3]
[-x_incr_outer/2, -outer_r, z0_outer], // [4]
[x_incr_outer/2, -outer_r, z0_outer + z_incr], // [5]
[x_incr_outer/2, -outer_r, thread_size - z0_outer + z_incr], // [6]
[-x_incr_outer/2, -outer_r, thread_size - z0_outer] // [7]
],
faces = [
[0, 3, 7, 4], // This-side trapezoid
[1, 5, 6, 2], // Back-side trapezoid
[0, 1, 2, 3], // Inner rectangle
[4, 7, 6, 5], // Outer rectangle
// These are not planar, so do with separate triangles.
[7, 2, 6], // Upper rectangle, bottom
[7, 3, 2], // Upper rectangle, top
[0, 5, 1], // Lower rectangle, bottom
[0, 4, 5] // Lower rectangle, top
]
);
}
}
}
}