// sphere diameter d = 30; cutoff = 3; c = 3; base = 10; screw_len = 15; screw_dia = 25.4/4; screw_head_len = 5; mount_screw_dia = 4; mount_screw_head_dia = 10; // retainer wire hole diameter retainer_dia = 1; splitter_tolerance = 0.2; e = 0.01; $fn = 500; use ; module screw() { translate([0, 0, 2*screw_head_len - screw_dia/2]) thread_imperial(1/16, screw_dia/25.4, 12, screw_len*16/25.4); intersection() { cylinder(r1=2*screw_head_len, r2=0, h=2*screw_head_len); cube([2*screw_head_len, 2*screw_head_len, 10*screw_head_len], center=true); } } module two_half_screws() for (i = [0,1]) translate([i*2*screw_head_len, -i*(screw_len + screw_head_len), 0]) intersection() { rotate([90, i*180, i*180]) screw(); translate([0, 0, 50]) cube(100, center=true); } module grip() for (i = [0:19]) rotate(i*360/20) translate([d/2-3, 0, -5/2]) cube([3,2,5]); module ball() difference() { // sphere with top and bottom cap removed sphere(d/2); for (i = [-1,1]) translate([0, 0, i * (d - cutoff)]) cube(d, center=true); // screw hole (thin ot the top, thickening in the center, big // square at the bottom) translate([0, 0, d/2 - cutoff - screw_len/2 + screw_head_len/2]) { cylinder(r=screw_dia/2, h=d, center=true); mirror([0, 0, 1]) intersection() { cylinder(r1=0, r2=d, h=d); cube([2*screw_head_len, 2*screw_head_len, 10*screw_head_len], center=true); } } // horizontal grip grip(); // vertical grip at the upper half sphere (but not at the top) difference() { rotate([90, -5, 0]) grip(); cylinder(r1=0, r2=sqrt(pow(d/2, 2) - pow(d/2-cutoff, 2)), h=d/2-cutoff); translate([0, 0, -d+4]) cylinder(r=d/2, h=d); } } module shell() { difference() { // sphere with cylinder to bottom mirror([0, 0, 1]) assign(r2=d/2+c) union() { sphere(r=r2); cylinder(r=r2, h=r2 + base); } // hollow out the sphere sphere(d/2); // add intro region translate([0, 0, d]) cube([d-2*cutoff, d*2, 2*d], center=true); // path for 1/4" screw; lets you rotate the sphere after // pushing it in (and allows later removal of it) hull() { cylinder(r=screw_dia/2, h=d); rotate([90, 0, 90]) cylinder(r=screw_dia/2, h=d); } // mounting screw hole assign(rs=mount_screw_dia) assign(rh=mount_screw_head_dia) union() { cylinder(r=rs/2, h=3*(d+base), center=true); translate([0, 0, -d/2-rh]) cylinder(r1=0, r2=rh/2, h=rh); translate([0, 0, -d/2 ]) cylinder(r=rh/2, h=d); } // holes for retainer wire for (i = [-1,1]) translate([i*d/4, 0, -d/2 - base/2 - c]) rotate([90, 0, 0]) cylinder(r=retainer_dia, h=2*d, center=true); } } module shell_splitter(e2=0) assign(w1 = d + 2*c + e) assign(w2 = mount_screw_head_dia + 2*c + e2) assign(h = base + c) translate([-w1/2, -w2/2, -h - d/2]) { cube([w1, w2, 2/3*h+e]); rotate([90, 0, 90]) translate([w2/2, 2/3*h, 0]) cylinder(h=w1, r=w2/2); translate([0, w2/2, 2/3*h]) rotate([45, 0, 0]) cube([w1, w2/2, w2/2]); } module shell_upper() difference() { shell(); translate([0, 0, -e]) shell_splitter(splitter_tolerance); } module shell_lower() intersection() { shell(); shell_splitter(); } module exploded_view() { translate([0, 0, -2*base]) shell_lower(); shell_upper(); translate([0,0,20]) rotate([90, 0, 90]) ball(); translate([-0.7*d - c - screw_len, 0, 20]) rotate(90) two_half_screws(); } module assembled_view() { shell_lower(); shell_upper(); assign(a=2 * (45 - acos((d - 2*cutoff) / d))) rotate([-a, 0, 90]) { ball(); screw(); } } exploded_view();