/* GNU AGPLv3 (or later at your option) see bottom for more license info */ /* spin thing that erin likes */ $fn = 75; layer_height = 0.35; weight = "penny"; // weight = "608zz"; //bearing = "608zz"; bearing = "sr188"; // bearing = "625rs"; weight_lip_overhang = 0.3; bearing_lip_overhang = weight_lip_overhang; wall = 3; penny_thickness = 1.52; penny_radius = 19.05 / 2; sr188_radius = 12.74 / 2; // 0.5 / 2 sr188_inner_radius = 6.3 / 2; // 0.2470 / 2 sr188_thickness = 4.8; // 0.1895 inch sr188_cover_radius = sr188_radius; sr188_cap_footprint_radius = 12 / 2; _608zz_radius = 22 / 2; _608zz_inner_radius = 8.1 / 2; _608zz_cover_radius = _608zz_radius; _608zz_cap_footprint_radius = 12 / 2; _608zz_thickness = 7; _625rs_radius = 16 / 2; _625rs_inner_radius = 5 / 2; _625rs_thickness = 5; _625rs_cover_radius = _625rs_radius; _625rs_cap_footprint_radius = _625rs_inner_radius + 1; weight_radius = (weight == "penny") ? penny_radius : _608zz_radius; weight_thickness = (weight == "penny") ? penny_thickness * 5 : _608zz_thickness; bearing_radius = (bearing == "608zz") ? _608zz_radius : (bearing == "625rs") ? _625rs_radius : (bearing == "sr188") ? sr188_radius : 1/0; bearing_window_radius = bearing_radius - bearing_lip_overhang - 1; bearing_inner_radius = (bearing == "608zz") ? _608zz_inner_radius : (bearing == "625rs") ? _625rs_inner_radius : (bearing == "sr188") ? sr188_inner_radius : 1/0; bearing_cover_radius = (bearing == "608zz") ? _608zz_cover_radius : (bearing == "625rs") ? _625rs_cover_radius : (bearing == "sr188") ? sr188_cover_radius : 1/0; bearing_cap_footprint_radius = (bearing == "608zz") ? _608zz_cap_footprint_radius : (bearing == "625rs" ) ? _625rs_cap_footprint_radius : (bearing == "sr188" ) ? sr188_cap_footprint_radius : 1/0; bearing_thickness = (bearing == "608zz") ? _608zz_thickness : (bearing == "625rs") ? _625rs_thickness : (bearing == "sr188") ? sr188_thickness : 1/0; spinner_height = penny_thickness * 5 + 2; arms = 3; module cap(bearing_inner_radius, bearing_cap_footprint_radius, bearing_cover_radius, bearing_thickness, bearing_window_radius) { footprint_height = 4.5; footprint_radius_safety = 0.2; cap_height = 3; bearing_thickness_safety = 0.6; finger_spot_height = cap_height * 2 / 3; stripes = 3; difference() { union() { cylinder(r1 = bearing_cover_radius - tan(30) * cap_height, r2 = bearing_cover_radius, h = cap_height); linear_extrude(height = cap_height + footprint_height - 1.05) { circle(bearing_window_radius - 1); } linear_extrude(height = cap_height + footprint_height) { circle(bearing_cap_footprint_radius - footprint_radius_safety); } linear_extrude(height = cap_height + footprint_height + bearing_thickness / 2 - bearing_thickness_safety) { circle(bearing_inner_radius + 0.1); } } translate([0, 0, -0.01]) { cylinder(r1 = bearing_inner_radius, r2 = bearing_inner_radius - tan(30) * finger_spot_height, h = finger_spot_height); for(stripe = [0 : stripes - 1]) { rotate((stripe / stripes) * 360) { linear_extrude(height = finger_spot_height) { polygon([[0, 0], [bearing_cover_radius * 2, 0], [cos(3 + 360 / (stripes * 2)) * bearing_cover_radius * 2, sin(3 + 360 / (stripes * 2)) * bearing_cover_radius * 2]]); } } } } } } module donut(height, footprint_radius) { bread_radius = height / 2; rotate_extrude() { translate([footprint_radius, 0]) { circle(bread_radius); } } } module donut_hole(height, footprint_radius) { difference() { cylinder(r = footprint_radius, h = height, center = true); donut(height, footprint_radius); } } module jelly_filled(height, footprint_radius) { cylinder(r = footprint_radius, h = height, center = true); donut(height, footprint_radius); } module fillet(r) { offset(r = -r) { offset(delta = r) { children(); } } } module mirrored(axis) { children(); mirror(axis) children(); } module spin_slice(weight_radius, bearing_radius, round_extra, wall, arms) { joiner_radius = (bearing_radius + weight_radius) / 2; // a = side along x axis a = bearing_radius + weight_radius + wall; // b = side from center to joiner b = bearing_radius + joiner_radius + round_extra; // c = side between joiner and arm center c = joiner_radius + weight_radius + round_extra; cos_C = (pow(a, 2) + pow(b, 2) - pow(c, 2)) / (2 * a * b); sin_C = sqrt(1 - pow(cos_C, 2)); bearing_xy = [0, 0]; weight_xy = [a, 0]; joiner_xy = [cos_C, sin_C] * b; for(arm = [0 : arms - 1]) { rotate(arm * (360 / arms)) { difference() { union() { translate(bearing_xy) { circle(bearing_radius + round_extra); } translate(weight_xy) { circle(weight_radius + round_extra); } mirrored([0, 1]) { polygon([bearing_xy, weight_xy, joiner_xy]); } } mirrored([0, 1]) { translate(joiner_xy) { circle(joiner_radius); } } } } } } module spin_cosine_slice(weight_radius, bearing_radius, round_extra, wall, arms) { /* in order to make a smooth transition from one arm to the next, follow the path of a circle just barely touching both arms and the center circle. this is referred to as the joiner circle. the joiner circle's radius and position are calculated using geometry. the center of the bearing, weight and joiner circle create a triangle. a = side between bearing and weight centers b = side between bearing and joiner centers c = side between joiner and weight centers A = angle opposite a, inside joiner B = angle opposite b, inside weight C = angle opposite c, inside bearing */ r0 = bearing_radius; r1 = weight_radius; // slightly cheated. calculated using 3 arms, C = 60. r2 = ((pow(r0, 2) + r0 * wall + r0 * r1 + pow(wall, 2) + 2 * r1 * wall + r0 * round_extra - wall * round_extra - 3 * r1 * round_extra) / (3 * r1 + wall - r0)); joiner_radius = r2; // a = side along x axis a = r0 + wall + r1; // b = side from center to joiner b = r0 + round_extra + r2; // c = side between joiner and arm center c = r1 + round_extra + r2; bearing_xy = [0, 0]; weight_xy = [a, 0]; joiner_xy = [cos(60), sin(60)] * b; translate(bearing_xy) { circle(bearing_radius + round_extra); } for(arm = [0 : arms - 1]) { rotate(arm * (360 / arms)) { translate(weight_xy) { circle(weight_radius + round_extra); } mirrored([0, 1]) { difference() { polygon([bearing_xy, weight_xy, joiner_xy]); translate(joiner_xy) { circle(joiner_radius); } } } } } } module spin_slices(weight_radius, weight_thickness, bearing_radius, bearing_thickness, weight_lip_overhang = 0.3, bearing_lip_overhang = 0.3, wall = 3, arms = 3, layer_height = 0.15) { thicker_thickness = (bearing_thickness > weight_thickness) ? bearing_thickness : weight_thickness; calculated_height = thicker_thickness + 2 * wall; layers = 2 * ceil(ceil(calculated_height / layer_height) / 2); actual_height = layers * layer_height; round_radius = actual_height / 2; /* rounding the outside edge of the spinner with a semi-circle leads to a shape that an overhang on the second layer several times the thickness of a printed extrusion width. rather than using a full semi-circle, this code aims to use just the portion in the middle, where the overhang is less severe */ old_start = 0; old_end = (layers / 2) - 1; /* add one to have some thickness all around weight holes for first layer */ new_start = old_end / 16 + 1; new_end = old_end; old_range = old_end - old_start; new_range = new_end - new_start; factor = new_range / old_range; /* initial adjacent is adjusted to (new start - 1) to allow some thickness all around weight holes on first layer */ initial_adjacent = round_radius - ((new_start - 1) * layer_height); initial_angle = acos(initial_adjacent / round_radius); initial_round_extra = initial_adjacent * tan(initial_angle); difference() { mirrored([0, 0, 1]) { for(layer = [0 : (layers / 2) - 1]) { translate([0, 0, layer * layer_height - actual_height / 2]) { linear_extrude(height = layer_height) { new_layer = (layer - old_start) * factor + new_start; adjacent = round_radius - (new_layer * layer_height); angle = acos(adjacent / round_radius); round_extra = adjacent * tan(angle) - initial_round_extra; spin_slice(weight_radius, bearing_radius, round_extra, wall, arms); } } } } cylinder(h = actual_height + 0.1, r = bearing_radius - bearing_lip_overhang, center = true); cylinder(h = bearing_thickness + 0.05, r = bearing_radius + 0.15, center = true); for(arm = [0 : arms - 1]) { rotate(arm * (360 / arms)) { translate([bearing_radius + wall + weight_radius, 0]) { cylinder(h = actual_height + 0.1, r = weight_radius - weight_lip_overhang, center = true); cylinder(h = weight_thickness + 0.05, r = weight_radius + 0.15, center = true); } } } } } module equilateral_triangle(radius){ polygon([[cos(0) * radius, sin(0) * radius], [cos(120) * radius, sin(120) * radius], [cos(240) * radius, sin(240) * radius]]); } module spin_cosine(weight_radius, weight_thickness, bearing_radius, bearing_thickness, weight_lip_overhang = 0.3, bearing_lip_overhang = 0.3, wall = 3, arms = 3, layer_height = 0.15) { thicker_thickness = (bearing_thickness > weight_thickness) ? bearing_thickness : weight_thickness; calculated_height = thicker_thickness + 2 * wall; layers = 2 * ceil(ceil(calculated_height / layer_height) / 2); actual_height = layers * layer_height; round_radius = actual_height / 2; /* rounding the outside edge of the spinner with a semi-circle leads to a shape that an overhang on the second layer several times the thickness of a printed extrusion width. rather than using a full semi-circle, this code aims to use just the portion in the middle, where the overhang is less severe */ old_start = 0; old_end = (layers / 2) - 1; /* add one to have some thickness all around weight holes for first layer */ new_start = old_end / 16 + 1; new_end = old_end; old_range = old_end - old_start; new_range = new_end - new_start; factor = new_range / old_range; /* initial adjacent is adjusted to (new start - 1) to allow some thickness all around weight holes on first layer */ initial_adjacent = round_radius - ((new_start - 1) * layer_height); initial_angle = acos(initial_adjacent / round_radius); initial_round_extra = initial_adjacent * tan(initial_angle); difference() { mirrored([0, 0, 1]) { for(layer = [0 : (layers / 2) - 1]) { translate([0, 0, layer * layer_height - actual_height / 2]) { linear_extrude(height = layer_height) { new_layer = (layer - old_start) * factor + new_start; adjacent = round_radius - (new_layer * layer_height); angle = acos(adjacent / round_radius); round_extra = adjacent * tan(angle) - initial_round_extra; spin_cosine_slice(weight_radius, bearing_radius, round_extra, wall, arms); } } } } // bearing window hole /*cylinder(h = actual_height + 0.1, r = bearing_radius - bearing_lip_overhang, center = true);*/ linear_extrude(height = actual_height + 0.1, center = true) { intersection() { equilateral_triangle(1.8 * bearing_radius); circle(bearing_radius + 0.1); } } // bearing cavity cylinder(h = bearing_thickness + 0.05, r = bearing_radius + 0.15, center = true); // arm holes for(arm = [0 : arms - 1]) { rotate(arm * (360 / arms)) { translate([bearing_radius + wall + weight_radius, 0]) { // weight window hole mirrored([0, 0, 1]) { translate([0, 0, (weight_thickness + 0.05) / 2]) { linear_extrude(height = wall + 0.1) { intersection(){ equilateral_triangle(1.8 * weight_radius); circle(weight_radius + 0.2); } } } } // weight cavity cylinder(h = weight_thickness + 0.05, r = weight_radius + 0.20, center = true); } } } } } module spin_donut(weight_radius, weight_thickness, bearing_radius, bearing_thickness, weight_lip_overhang, bearing_lip_overhang, wall, arms) { thicker_thickness = (bearing_thickness > weight_thickness) ? bearing_thickness : weight_thickness; height = thicker_thickness + wall * 2; center_to_arm_center = bearing_radius + wall + weight_radius; jelly_filled(height, bearing_radius); for(arm = [0 : arms]) { rotate(arm * (360 / arms)) { translate([center_to_arm_center, 0, 0]) { jelly_filled(height, weight_radius); } } } } /* This file is part of 3d-printables. 3d-printables is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 3d-printables 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with challenge-bot. If not, see . */