diff --git a/bearings.scad b/bearings.scad new file mode 100644 index 0000000..0467ae3 --- /dev/null +++ b/bearings.scad @@ -0,0 +1,9 @@ +//Todo: placeholder; should generate standard + cusom bearing mounting holes +module bearing_hole(outer_radius, hole=true, mochup=true) +{ + union() + { + if (mochup==true) %translate([0,0,-1.5])cylinder(r=outer_radius,h=3); + if (hole==true) circle(r=outer_radius); + } +} diff --git a/gears.scad b/gears.scad new file mode 100644 index 0000000..d264912 --- /dev/null +++ b/gears.scad @@ -0,0 +1,171 @@ +//test +// gear(number_of_teeth=11,diametral_pitch=17); +translate([(51+17)*200/360+1.15,0]) rotate(-0.02) + gear(number_of_teeth=51,circular_pitch=200); + gear(number_of_teeth=17,circular_pitch=200); + translate([-50,0]) gear(number_of_teeth=17,diametral_pitch=2); + +//test(); + +module test() +{ +for (i=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]) +{ + //echo(polar_to_cartesian([involute_intersect_angle( 0.1,i) , i ])); + translate(polar_to_cartesian([involute_intersect_angle( 0.1,i) , i ])) circle($fn=15, r=0.5); + + //translate( involute_intersection_point(0.1,i,0) ) circle($fn=15, r=0.5); +} +} + + +// circular_pitch = pitch_diameter*180/ number_of_teeth; + + +// Geometry Sources: +// http://www.cartertools.com/involute.html +// gears.py (inkscape extension: /usr/share/inkscape/extensions/gears.py) +// Usage: +// Diametral pitch: Number of teeth per unit length. +// Circular pitch: Length of the arc from one tooth to the next +// Clearance: Radial distance between top of tooth on one gear to bottom of gap on another. + +module gear(number_of_teeth, + circular_pitch=false, diametrial_pitch=false, + pressure_angle=20, clearance = 0) +{ + if (circular_pitch==false && diametrical_pitch==false) echo("MCAD ERROR: gear module needs either a diametrical_pitch or circular_pitch"); + + //Convert diametrial pitch to our native circular pitch + circular_pitch = (circular_pitch!=false?circular_pitch:180/diametral_pitch); + + // Pitch diameter: Diameter of pitch circle. + pitch_diameter = number_of_teeth * circular_pitch / 180; + pitch_radius = pitch_diameter/2; + + // Base Circle + base_diameter = pitch_diameter*cos(pressure_angle); + base_radius = base_diameter/2; + + // Diametrial pitch: Number of teeth per unit length. + pitch_diametrial = number_of_teeth / pitch_diameter; + + // Addendum: Radial distance from pitch circle to outside circle. + addendum = 1/pitch_diametrial; + + //Outer Circle + outer_radius = pitch_radius+addendum; + outer_diameter = outer_radius*2; + + // Dedendum: Radial distance from pitch circle to root diameter + dedendum = addendum + clearance; + + // Root diameter: Diameter of bottom of tooth spaces. + root_radius = pitch_radius-dedendum; + root_diameter = root_radius * 2; + + half_thick_angle = 360 / (4 * number_of_teeth); + echo(half_thick_angle); + + union() + { + rotate(half_thick_angle) circle($fn=number_of_teeth*2, r=root_radius*1.001); + + for (i= [1:number_of_teeth]) + //for (i = [0]) + { + rotate([0,0,i*360/number_of_teeth]) + { + involute_gear_tooth( + pitch_radius = pitch_radius, + root_radius = root_radius, + base_radius = base_radius, + outer_radius = outer_radius, + half_thick_angle = half_thick_angle); + } + } + } +} + + +module involute_gear_tooth( + pitch_radius, + root_radius, + base_radius, + outer_radius, + half_thick_angle + ) +{ + pitch_to_base_angle = involute_intersect_angle( base_radius, pitch_radius ); + + outer_to_base_angle = involute_intersect_angle( base_radius, outer_radius ); + + //echo(base_radius); + //echo(outer_radius); + //echo(outer_to_base_angle); + echo(acos(base_radius/pitch_radius)); + + base1 = 0 - pitch_to_base_angle - half_thick_angle; + pitch1 = 0 - half_thick_angle; + outer1 = outer_to_base_angle - pitch_to_base_angle - half_thick_angle; + + b1 = polar_to_cartesian([ base1, base_radius ]); + p1 = polar_to_cartesian([ pitch1, pitch_radius ]); + o1 = polar_to_cartesian([ outer1, outer_radius ]); + + b2 = polar_to_cartesian([ -base1, base_radius ]); + p2 = polar_to_cartesian([ -pitch1, pitch_radius ]); + o2 = polar_to_cartesian([ -outer1, outer_radius ]); + + // ( root_radius > base_radius variables ) + pitch_to_root_angle = pitch_to_base_angle - involute_intersect_angle(base_radius, root_radius ); + root1 = pitch1 - pitch_to_root_angle; + root2 = -pitch1 + pitch_to_root_angle; + r1_t = polar_to_cartesian([ root1, root_radius ]); + r2_t = polar_to_cartesian([ -root1, root_radius ]); + + // ( else ) + r1_f = polar_to_cartesian([ base1, root_radius ]); + r2_f = polar_to_cartesian([ -base1, root_radius ]); + + if (root_radius > base_radius) + { + echo("true"); + polygon( points = [ + r1_t,p1,o1,o2,p2,r2_t + ], convexity = 3); + } + else + { + polygon( points = [ + r1_f, b1,p1,o1,o2,p2,b2,r2_f + ], convexity = 3); + } + +} + + + +// Finds the angle of the involute about the base radius at the given distance (radius) from it's center. +//source: http://www.mathhelpforum.com/math-help/geometry/136011-circle-involute-solving-y-any-given-x.html + +function involute_intersect_angle(base_radius, radius) = sqrt( pow(radius/base_radius,2) - 1); + + + +// Polar coord [angle, radius] to cartesian coord [x,y] + +function polar_to_cartesian(polar) = [ + polar[1]*cos(polar[0]), + polar[1]*sin(polar[0]) +]; + + +// == LEGACY == +// Finds the intersection of the involute about the base radius with a cricle of the given radius in cartesian coordinates [x,y]. + +//function involute_intersection_point(base_radius, radius, zero_angle) = polar_to_cartesian([ involute_intersect_angle(base_radius, radius)-zero_angle , radius ]); + +//function rotation_matrix(degrees) = [ [cos(degrees), -sin(degrees)] , [sin(degrees), cos(degrees)] ]; + +//function involute_intersect_angle(base_radius, radius) = sqrt( pow(radius,2) - pow(base_radius,2) ) / base_radius - acos(base_radius / radius); diff --git a/math.scad b/math.scad new file mode 100644 index 0000000..ca1f211 --- /dev/null +++ b/math.scad @@ -0,0 +1,4 @@ +PI = 3.14159; + +// translates a imperial measurement in inches to meters +mm_per_inche =25.4; diff --git a/motors.scad b/motors.scad new file mode 100644 index 0000000..745b1ed --- /dev/null +++ b/motors.scad @@ -0,0 +1,92 @@ +include + + +//generates a motor mount for the specified nema standard #. +module stepper_motor_mount(nema_standard,slide_distance=0, mochup=true) +{ + //dimensions from: + // http://www.numberfactory.com/NEMA%20Motor%20Dimensions.htm + if (nema_standard == 17) + { + _stepper_motor_mount( + motor_shaft_diameter = 0.1968*mm_per_inche, + motor_shaft_length = 0.945*mm_per_inche, + pilot_diameter = 0.866*mm_per_inche, + pilot_length = 0.80*mm_per_inche, + mounting_bolt_circle = 1.725*mm_per_inche, + bolt_hole_size = 3.5, + bolt_hole_distance = 1.220*mm_per_inche, + slide_distance = slide_distance, + mochup = mochup); + } + if (nema_standard == 23) + { + _stepper_motor_mount( + motor_shaft_diameter = 0.250*mm_per_inche, + motor_shaft_length = 0.81*mm_per_inche, + pilot_diameter = 1.500*mm_per_inche, + pilot_length = 0.062*mm_per_inche, + mounting_bolt_circle = 2.625*mm_per_inche, + bolt_hole_size = 0.195*mm_per_inche, + bolt_hole_distance = 1.856*mm_per_inche, + slide_distance = slide_distance, + mochup = mochup); + } + +} + + +//inner mehod for creating a stepper motor mount of any dimensions +module _stepper_motor_mount( + motor_shaft_diameter, + motor_shaft_length, + pilot_diameter, + pilot_length, + mounting_bolt_circle, + bolt_hole_size, + bolt_hole_distance, + slide_distance = 0, + motor_length = 40, //arbitray - not standardized + mochup +) +{ + union() + { + // == centered mount points == + //mounting circle inset + translate([0,slide_distance/2,0]) circle(r = pilot_diameter/2); + square([pilot_diameter,slide_distance],center=true); + translate([0,-slide_distance/2,0]) circle(r = pilot_diameter/2); + + //todo: motor shaft hole + + //mounting screw holes + for (x = [-1,1]) + { + for (y = [-1,1]) + { + translate([x*bolt_hole_distance/2,y*bolt_hole_distance/2,0]) + { + translate([0,slide_distance/2,0]) circle(bolt_hole_size/2); + translate([0,-slide_distance/2,0]) circle(bolt_hole_size/2); + square([bolt_hole_size,slide_distance],center=true); + } + } + } + // == motor mock-up == + //motor box + if (mochup == true) + { + %translate([0,0,-5]) cylinder(h = 5, r = pilot_diameter/2); + %translate(v=[0,0,-motor_length/2]) + { + cube(size=[bolt_hole_distance+bolt_hole_size+5,bolt_hole_distance+bolt_hole_size+5,motor_length], center = true); + } + //shaft + %translate(v=[0,0,-(motor_length-motor_shaft_length-2)/2]) + { + %cylinder(r=motor_shaft_diameter/2,h=motor_length+motor_shaft_length--1, center = true); + } + } + }; +} \ No newline at end of file diff --git a/nuts_and_bolts.scad b/nuts_and_bolts.scad new file mode 100644 index 0000000..4311665 --- /dev/null +++ b/nuts_and_bolts.scad @@ -0,0 +1,179 @@ +//testNutsAndBolts(); + +module testNutsAndBolts() +{ + $fn = 360; + translate([0,15])nutHole(3, proj=2); + boltHole(3, length= 30, proj=2); +} + +MM = "mm"; +INCH = "inch"; //Not yet supported + +//Based on: http://www.roymech.co.uk/Useful_Tables/Screws/Hex_Screws.htm +METRIC_NUT_AC_WIDTHS = +[ + -1, //0 index is not used but reduces computation + -1, + -1, + 6.40,//m3 + 8.10,//m4 + 9.20,//m5 + 11.50,//m6 + -1, + 15.00,//m8 + -1, + 19.60,//m10 + -1, + 22.10,//m12 + -1, + -1, + -1, + 27.70,//m16 + -1, + -1, + -1, + 34.60,//m20 + -1, + -1, + -1, + 41.60,//m24 + -1, + -1, + -1, + -1, + -1, + 53.1,//m30 + -1, + -1, + -1, + -1, + -1, + 63.5//m36 +]; +METRIC_NUT_THICKNESS = +[ + -1, //0 index is not used but reduces computation + -1, + -1, + 2.40,//m3 + 3.20,//m4 + 4.00,//m5 + 5.00,//m6 + -1, + 6.50,//m8 + -1, + 8.00,//m10 + -1, + 10.00,//m12 + -1, + -1, + -1, + 13.00,//m16 + -1, + -1, + -1, + 16.00//m20 + -1, + -1, + -1, + 19.00,//m24 + -1, + -1, + -1, + -1, + -1, + 24.00,//m30 + -1, + -1, + -1, + -1, + -1, + 29.00//m36 +]; + +COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS = +[//based on max values + -1, //0 index is not used but reduces computation + -1, + -1, + 2.98,//m3 + 3.978,//m4 + 4.976,//m5 + 5.974,//m6 + -1, + 7.972,//m8 + -1, + 9.968,//m10 + -1, + 11.966,//m12 + -1, + -1, + -1, + 15.962,//m16 + -1, + -1, + -1, + 19.958,//m20 + -1, + -1, + -1, + 23.952,//m24 + -1, + -1, + -1, + -1, + -1, + 29.947,//m30 + -1, + -1, + -1, + -1, + -1, + 35.940//m36 +]; + +module nutHole(size, units=MM, tolerance = +0.0001, proj = -1) +{ + //takes a metric screw/nut size and looksup nut dimensions + radius = METRIC_NUT_AC_WIDTHS[size]/2+tolerance; + height = METRIC_NUT_THICKNESS[size]+tolerance; + if (proj == -1) + { + cylinder(r= radius, h=height, $fn = 6, center=[0,0]); + } + if (proj == 1) + { + circle(r= radius, $fn = 6); + } + if (proj == 2) + { + translate([-radius/2, 0]) + square([radius*2, height]); + } +} + +module boltHole(size, units=MM, length, tolerance = +0.0001, proj = -1) +{ + radius = COURSE_METRIC_BOLT_MAJOR_THREAD_DIAMETERS[size]/2+tolerance; +//TODO: proper screw cap values + capHeight = METRIC_NUT_THICKNESS[size]+tolerance; //METRIC_BOLT_CAP_HEIGHTS[size]+tolerance; + capRadius = METRIC_NUT_AC_WIDTHS[size]/2+tolerance; //METRIC_BOLT_CAP_RADIUS[size]+tolerance; + + if (proj == -1) + { + translate([0, 0, -capHeight]) + cylinder(r= capRadius, h=capHeight); + cylinder(r = radius, h = length); + } + if (proj == 1) + { + circle(r = radius); + } + if (proj == 2) + { + translate([-capRadius/2, -capHeight]) + square([capRadius*2, capHeight]); + square([radius*2, length]); + } +} \ No newline at end of file