update puzzle to latest version to match solution instructions
[ozzloy@gmail.com/3d-printables] / spin-data.scad
index 0c83d85bcad1a929d25e26a26e08fcd362b2cd9e..e5df4e2aa718930ecff0a5909ca9d037a351f7f2 100644 (file)
@@ -2,39 +2,71 @@
    see bottom for more license info */
 
 /* spin thing that erin likes */
-$fn = 50;
+$fn = 75;
 
-layer_height = 0.15;
+layer_height = 0.35;
 
 weight = "penny";
 // weight = "608zz";
-bearing = "608zz";
+
+//bearing = "608zz";
+bearing = "sr188";
+// bearing = "625rs";
+
 weight_lip_overhang = 0.3;
 bearing_lip_overhang = weight_lip_overhang;
-// TODO: switch wall_thickness -> wall
-wall_thickness = 3;
 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 = 19.4 / 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 : 1/0;
-bearing_inner_radius = (bearing == "608zz") ? _608zz_inner_radius : 1/0;
-bearing_cover_radius = (bearing == "608zz")
-                       ? _608zz_cover_radius + wall
-                       : 1/0;
+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 : 1/0;
-bearing_thickness = (bearing == "608zz") ? _608zz_thickness : 1/0;
+  (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;
@@ -42,62 +74,171 @@ arms = 3;
 module cap(bearing_inner_radius,
            bearing_cap_footprint_radius,
            bearing_cover_radius,
-           bearing_thickness) {
-  footprint_height = 1.6;
-  footprint_radius_safety = 0.25;
+           bearing_thickness,
+           bearing_window_radius) {
+  footprint_height = 4.5;
+  footprint_radius_safety = 0.2;
   cap_height = 3;
-  bearing_cover_radius_safety = 0.75;
-  bearing_thickness_safety = 0.2;
+  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); } }
+        circle(bearing_inner_radius + 0.1); } }
     translate([0, 0, -0.01]) {
-      cylinder(r1 = bearing_inner_radius + tan(30) * (cap_height - 1),
-               r2 = bearing_inner_radius,
-               h = cap_height - 1); } } }
+      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 spin_footprint(weight_radius,
-                      bearing_radius,
-                      round_extra,
-                      wall,
-                      arms) {
-  thinner_radius = (bearing_radius < weight_radius)?
-    bearing_radius : weight_radius;
-  fillet(thinner_radius / 2) {
-    for(arm = [0 : arms - 1]) {
-      hull() {
-        circle(bearing_radius + round_extra);
-        rotate( (arm / arms) * 360 ) {
-          translate([bearing_radius + wall + weight_radius, 0]) {
-            circle(weight_radius + round_extra); } } } } } }
-
 module mirrored(axis) {
   children();
   mirror(axis) children(); }
 
-module spin(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) {
-  layer_height = 0.15;
+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;
@@ -105,10 +246,18 @@ module spin(weight_radius,
   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;
 
-  new_start = old_end / 16;
+  /* 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;
@@ -116,24 +265,151 @@ module spin(weight_radius,
 
   factor = new_range / old_range;
 
-  initial_adjacent = round_radius - (new_start * layer_height);
+  /* 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);
-  
-  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;
-          echo(round_extra);
-          spin_footprint(weight_radius,
-                         bearing_radius,
-                         round_extra,
-                         wall,
-                         arms); } } } } }
+
+  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.