Loading

Cycloidal Speed Reducer in OpenSCAD

by mattmoses, published

Cycloidal Speed Reducer in OpenSCAD by mattmoses May 8, 2011

Featured Thing!

Thing Info

23079Views 7254Downloads
Report Thing

Summary

By request of Syvwlch ( http://www.thingiverse.com/syvwlch ) and WilliamAAdams ( http://www.thingiverse.com/WilliamAAdams ), here is a stand-alone public-domain OpenSCAD cycloidal speed reducer. As with the Wankel Engine and Roots Blower I recently posted, this is intended more as an example of an interesting mechanism than as a practical device. If you want a practical printable speed reducer, you might consider one of the other alternatives like

the worm drives on this Tank http://www.thingiverse.com/thing:8080 or
differential planetary gears http://www.thingiverse.com/thing:7390 or
cascaded spur gears http://www.thingiverse.com/thing:7379 or
this planetary gear reducer http://www.thingiverse.com/thing:8460

There are several cycloidal-type mechanisms already on Thingiverse, such as
http://www.thingiverse.com/thing:3617 and http://www.thingiverse.com/thing:3736

There are also several interesting external sites like:
http://www.zincland.com/hypocycloid/
http://fabricationsofthemind.com/2010/07/09/extruder-design-1-printable-1001-hypocycloidal-gearbox/
https://github.com/triffid/Differential_Hypocycloid
http://reprap.org/wiki/Differential_Hypocycloid
http://en.wikipedia.org/wiki/Gerotor
http://en.wikipedia.org/wiki/Gear_pump

and many many interesting youtube videos such as
http://www.youtube.com/watch?v=bRn1K2XeWVE
http://www.youtube.com/watch?v=3WvPF6uGCq4
http://www.youtube.com/watch?v=CG2sPuqEXBg
http://www.youtube.com/watch?v=AMtyFwMDL7w
http://www.youtube.com/watch?v=h236SP86nnQ

This present script is based on a design by M.F. Hill described in his 1928 patent "Internal Rotor", number 1,682,563:

http://www.google.com/patents/about?id=mdF5AAAAEBAJ&dq=1682563

Note that this design is based on an offset hypocycloid, similar to Figure I in Hill's patent. Most of the contemporary designs appear to be based on an offset epicycloid, more closely resembling Figure V in the patent.

The motivated student can modify the code so it generates epicycloidal-based profiles. Hint: start by making a module ``epitrochoidBandFast(n, r, thickness, r_off)". The motivated student could also probably clean up my train-wreck of code and/or figure out how to do arrays in OpenSCAD.

Note also that these rotors can be used for pumps - see the gifs in the comments for an example.

Instructions

OpenSCAD for animate!
STLs for print!
DXF for cut!

The minimum clearance around shafts is about 0.6mm. If printed, there might be a little interference at the tips of the internal rotor lobes. The DXFs have the same profile as the STLs, so the beam kerf should provide ample clearance if anyone actually lasercuts it. There are some extra holes in the DXF profiles so pieces can be aligned and bolted/screwed together.

Yet-another-Note: The DXF files were generated directly from OpenSCAD. I am not sure why they preview as having dotted lines in some places, but when viewed with say, Open Office Draw, the lines appear solid.

Thing Info

23079Views 7254Downloads
Report Thing

Makes

Liked By

View All

Give a Shout Out

If you print this Thing and display it in public proudly give attribution by printing and displaying this tag. Print Thing Tag

All Apps

This extension connects Thingiverse with Makeprintable, a cloud-based mesh repair service that analyzes, validates and repairs most common mesh errors that can occur when preparing a 3D design file...

App Info Launch App

Kiri:Moto is an integrated cloud-based slicer and tool-path generator for 3D Printing, CAM / CNC and Laser cutting. *** 3D printing mode provides model slicing and GCode output using built-in...

App Info Launch App
KiriMoto Thing App
Feb 5, 2016 - Modified Feb 5, 2016

Here is a version of Hypotrochoid Band Fast that uses arrays, so has configurable precision, I commented out the original hardcoded calculations for reference

//===========================================
// Hypotrochoid Band Fast
//
// This generates the normal vector to a hypocycloid, pointing outward,
// and extrudes a profile approximating the envelope of normals.
//
// n        is the number of lobes
// r        is the radius of the little rolling circle that generates the hypocycloid
// thickness    is the height of extrusion
// r_off    is the distance that the envelope is offset from the base hypocycloid
// 
// When r_off = zero the output is the same as a hypocycloid.
//
// As far as I know, OpenSCAD does not do arrays, hence the funny big blocks of
// hardcoded numbers you will see below.
//
module hypotrochoidBandFast(n, r, thickness, r_off) {
    s = $fn == 0 ? ceil(r*PI*2/$fs) : ceil($fn/r/2); // s calculated from $fs or $fn, or hardcode this to 15 for original steps

    R = r*n;
    d = r;

    // set to 1 for normal size cylinders.  this will leave a tiny cusp in some cases that does
    // not blend in to cylinders.  see below for details.  make hideCuspFactor larger to scale up
    // the cylinders slightly. 1.01 seems to work OK.
    hideCuspFactor = 1.01;

    // dth stands for dtheta - i.e. a small change of the angle "theta"
    // there are 14 intermediate points on the curve, so a wedge is
    // divided into 14 + 1 = 15.  You may be tempted to change this, but it really is 15.
    dth = 360/n/s;

    // X points on base hypotrochoid
    xbStart = (R-r) + d;
    xbEnd =  (R-r)*cos(360/n) + d*cos((R-r)/r*360/n);   

    // Instead of an array and a for-loop we just hard-code these 
    // intermediate points, this if for X coords on the base hypocycloid.
    //

    xbb = [for (i=[1:s-1]) (R-r)*cos(dth*i) + d*cos((R-r)/r*dth*i) ];
    /*
    xb1 = (R-r)*cos(dth*1) + d*cos((R-r)/r*dth*1);
    xb2 = (R-r)*cos(dth*2) + d*cos((R-r)/r*dth*2);
    xb3 = (R-r)*cos(dth*3) + d*cos((R-r)/r*dth*3);
    xb4 = (R-r)*cos(dth*4) + d*cos((R-r)/r*dth*4);
    xb5 = (R-r)*cos(dth*5) + d*cos((R-r)/r*dth*5);
    xb6 = (R-r)*cos(dth*6) + d*cos((R-r)/r*dth*6);
    xb7 = (R-r)*cos(dth*7) + d*cos((R-r)/r*dth*7);  
    xb8 = (R-r)*cos(dth*8) + d*cos((R-r)/r*dth*8);
    xb9 = (R-r)*cos(dth*9) + d*cos((R-r)/r*dth*9);
    xb10 = (R-r)*cos(dth*10) + d*cos((R-r)/r*dth*10);
    xb11 = (R-r)*cos(dth*11) + d*cos((R-r)/r*dth*11);
    xb12 = (R-r)*cos(dth*12) + d*cos((R-r)/r*dth*12);
    xb13 = (R-r)*cos(dth*13) + d*cos((R-r)/r*dth*13);
    xb14 = (R-r)*cos(dth*14) + d*cos((R-r)/r*dth*14);
    */

    // Y points on base hypotrochoid
    ybStart = 0;
    ybEnd =   (R-r)*sin(360/n) - d*sin((R-r)/r*360/n);

    // Instead of an array and a for-loop we just hard-code these 
    // intermediate points, this if for Y coords on the base hypocycloid.
    //
    ybb = [for (i=[1:s-1]) (R-r)*sin(dth*i) - d*sin((R-r)/r*dth*i) ];
    /*
    yb1 =  (R-r)*sin(dth*1) - d*sin((R-r)/r*dth*1);
    yb2 =  (R-r)*sin(dth*2) - d*sin((R-r)/r*dth*2);
    yb3 =  (R-r)*sin(dth*3) - d*sin((R-r)/r*dth*3);
    yb4 =  (R-r)*sin(dth*4) - d*sin((R-r)/r*dth*4);
    yb5 =  (R-r)*sin(dth*5) - d*sin((R-r)/r*dth*5);
    yb6 =  (R-r)*sin(dth*6) - d*sin((R-r)/r*dth*6);
    yb7 =  (R-r)*sin(dth*7) - d*sin((R-r)/r*dth*7);
    yb8 =  (R-r)*sin(dth*8) - d*sin((R-r)/r*dth*8);
    yb9 =  (R-r)*sin(dth*9) - d*sin((R-r)/r*dth*9);
    yb10 =  (R-r)*sin(dth*10) - d*sin((R-r)/r*dth*10);
    yb11 =  (R-r)*sin(dth*11) - d*sin((R-r)/r*dth*11);
    yb12 =  (R-r)*sin(dth*12) - d*sin((R-r)/r*dth*12);
    yb13 =  (R-r)*sin(dth*13) - d*sin((R-r)/r*dth*13);
    yb14 =  (R-r)*sin(dth*14) - d*sin((R-r)/r*dth*14);
    */

    // Now we do the offset points.  The tangent to the
    // hypotrochoid is [dx/dtheta, dy/dtheta].
    // We take the tangent, normalize it, rotate it, and scale it 
    // to get the offsets in X and Y coords.

    // X offset points
    xfStart = 0;
    xfEnd =  r_off*cos(360/n - 90);

    // hard-coded offset points for X
    //
    xff = [for (i=[1:s-1]) (R-r)*cos(dth*i) - r*cos( (R-r)/r*dth*i) * (R-r)/r ];
    /*
    xf1 = (R-r)*cos(dth*1) - r*cos( (R-r)/r*dth*1) * (R-r)/r ;
    xf2 = (R-r)*cos(dth*2) - r*cos( (R-r)/r*dth*2) * (R-r)/r ;
    xf3 = (R-r)*cos(dth*3) - r*cos( (R-r)/r*dth*3) * (R-r)/r ;
    xf4 = (R-r)*cos(dth*4) - r*cos( (R-r)/r*dth*4) * (R-r)/r ;
    xf5 = (R-r)*cos(dth*5) - r*cos( (R-r)/r*dth*5) * (R-r)/r ;
    xf6 = (R-r)*cos(dth*6) - r*cos( (R-r)/r*dth*6) * (R-r)/r ;
    xf7 = (R-r)*cos(dth*7) - r*cos( (R-r)/r*dth*7) * (R-r)/r ;  
    xf8 = (R-r)*cos(dth*8) - r*cos( (R-r)/r*dth*8) * (R-r)/r ;
    xf9 = (R-r)*cos(dth*9) - r*cos( (R-r)/r*dth*9) * (R-r)/r ;
    xf10 = (R-r)*cos(dth*10) - r*cos( (R-r)/r*dth*10) * (R-r)/r ;
    xf11 = (R-r)*cos(dth*11) - r*cos( (R-r)/r*dth*11) * (R-r)/r ;
    xf12 = (R-r)*cos(dth*12) - r*cos( (R-r)/r*dth*12) * (R-r)/r ;
    xf13 = (R-r)*cos(dth*13) - r*cos( (R-r)/r*dth*13) * (R-r)/r ;
    xf14 = (R-r)*cos(dth*14) - r*cos( (R-r)/r*dth*14) * (R-r)/r ;   
    */

    // Y offset points
    yfStart = r_off;
    yfEnd =  r_off*sin(360/n - 90);

    yff = [for (i=[1:s-1]) (R-r)*sin(dth*i) + r*sin( (R-r)/r*dth*i) * (R-r)/r ];
    /*
    yf1 =  (R-r)*sin(dth*1) + r*sin( (R-r)/r*dth*1) * (R-r)/r ;
    yf2 =  (R-r)*sin(dth*2) + r*sin( (R-r)/r*dth*2) * (R-r)/r ;
    yf3 =  (R-r)*sin(dth*3) + r*sin( (R-r)/r*dth*3) * (R-r)/r ;
    yf4 =  (R-r)*sin(dth*4) + r*sin( (R-r)/r*dth*4) * (R-r)/r ;
    yf5 =  (R-r)*sin(dth*5) + r*sin( (R-r)/r*dth*5) * (R-r)/r ;
    yf6 =  (R-r)*sin(dth*6) + r*sin( (R-r)/r*dth*6) * (R-r)/r ;
    yf7 =  (R-r)*sin(dth*7) + r*sin( (R-r)/r*dth*7) * (R-r)/r ;
    yf8 =  (R-r)*sin(dth*8) + r*sin( (R-r)/r*dth*8) * (R-r)/r ;
    yf9 =  (R-r)*sin(dth*9) + r*sin( (R-r)/r*dth*9) * (R-r)/r ;
    yf10 =  (R-r)*sin(dth*10) + r*sin( (R-r)/r*dth*10) * (R-r)/r ;
    yf11 =  (R-r)*sin(dth*11) + r*sin( (R-r)/r*dth*11) * (R-r)/r ;
    yf12 =  (R-r)*sin(dth*12) + r*sin( (R-r)/r*dth*12) * (R-r)/r ;
    yf13 =  (R-r)*sin(dth*13) + r*sin( (R-r)/r*dth*13) * (R-r)/r ;
    yf14 =  (R-r)*sin(dth*14) + r*sin( (R-r)/r*dth*14) * (R-r)/r ;
    */

    mm = [for (i=[0:s-2]) sqrt(xff[i]*xff[i] + yff[i]*yff[i])/r_off ];
    /*
    m1 = sqrt(xf1*xf1 + yf1*yf1)/r_off;
    m2 = sqrt(xf2*xf2 + yf2*yf2)/r_off;
    m3 = sqrt(xf3*xf3 + yf3*yf3)/r_off;
    m4 = sqrt(xf4*xf4 + yf4*yf4)/r_off;
    m5 = sqrt(xf5*xf5 + yf5*yf5)/r_off;
    m6 = sqrt(xf6*xf6 + yf6*yf6)/r_off;
    m7 = sqrt(xf7*xf7 + yf7*yf7)/r_off;
    m8 = sqrt(xf8*xf8 + yf8*yf8)/r_off;
    m9 = sqrt(xf9*xf9 + yf9*yf9)/r_off;
    m10 = sqrt(xf10*xf10 + yf10*yf10)/r_off;
    m11 = sqrt(xf11*xf11 + yf11*yf11)/r_off;
    m12 = sqrt(xf12*xf12 + yf12*yf12)/r_off;
    m13 = sqrt(xf13*xf13 + yf13*yf13)/r_off;
    m14 = sqrt(xf14*xf14 + yf14*yf14)/r_off;
    */

// Now that we have the points, we make a polygon and extrude it.

union() {
for  ( i = [0:n-1] ) {
rotate([0,0, 360/n*i]) {

    linear_extrude(height = thickness)
        // the first point in the polygon is moved slightly off the origin
         polygon(points= concat([
            [-R/20 * cos(360/n/2) , -R/20 * sin(360/n/2)],
            [xbStart, ybStart],
            [xbStart + xfStart, ybStart + yfStart]],

            [ for (i=[0:s-2]) ([xbb[i] + xff[i]/mm[i], ybb[i] + yff[i]/mm[i]]) ]
            /*
            [xb1 + xf1/m1, yb1 + yf1/m1], 
            [xb2 + xf2/m2, yb2 + yf2/m2], 
            [xb3 + xf3/m3, yb3 + yf3/m3], 
            [xb4 + xf4/m4, yb4 + yf4/m4], 
            [xb5 + xf5/m5, yb5 + yf5/m5], 
            [xb6 + xf6/m6, yb6 + yf6/m6], 
            [xb7 + xf7/m7, yb7 + yf7/m7], 
            [xb8 + xf8/m8, yb8 + yf8/m8], 
            [xb9 + xf9/m9, yb9 + yf9/m9], 
            [xb10 + xf10/m10, yb10 + yf10/m10], 
            [xb11 + xf11/m11, yb11 + yf11/m11], 
            [xb12 + xf12/m12, yb12 + yf12/m12], 
            [xb13 + xf13/m13, yb13 + yf13/m13], 
            [xb14 + xf14/m14, yb14 + yf14/m14], 
            */
            ,
            [

            [xbEnd + xfEnd, ybEnd + yfEnd],
            [xbEnd, ybEnd]]),
            paths = [concat([0],[for(i=[1:s+4]) s-i+5])],
            // paths = [[0,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1]],
            convexity = 10);

    // If you look at just the wedge extruded above, without the cylinders below,
    // you can see a small cusp as the band radius gets larger.  The radius of 
    // the cylinder is manually increased a slight bit so that the cusp is contained 
    // within the cylinder.  With unlimited resolution, the cusp and cylinder would
    // blend together perfectly (I think), but this workaround is needed because
    // we are only using piecewise linear approximations to these curves.

    translate([xbStart, ybStart, thickness/2])
        cylinder(r = hideCuspFactor*r_off, h = thickness, center = true);

} //end rotate

} //end for

} // end union()

} // end module hypotrochoidBandFast
//=========================================== 

I suppose the reduction ratio is 1:9, does anyone know if that's right?

8 turns on the input equals 1 turn on the output. There are more details in the comments in the OpenSCAD code.

Does anyone have actual solid part files for a cycloidal speed reducer?

Very good thing!

I guess

cycloid eccentric.stl

and

cycloid driven shaft.stl

are the weakest points in it.

Did you try to either taper these shafts and their holes for added strength

or allow to replace the shafts by bolts?

Looks like it could transfer much more force that way.

(And with 8:1 I guess you get a lot of force.)

Tapering or replacing by bolts is a good idea, but I have not added anything like that. There are probably a number of practical problems that would need to be solved if someone wanted to use this in a real application. It would also probably be necessary to add some type of ball or roller bearing to the eccentric to reduce friction. The pin extrusions on the driven shaft may also have to be replaced with rollers.

Awesome! :)

You can do one dimensional numeric arrays like so:

myArray = [1, 2, 3];
for (i = [0:2]) 
{
    echo("", myArray[i]);
}

Arrays are zero indexed.

Cool, thanks! That will help clean up the code. Do you know if there is a way to pass a generic array of points to polygon()?

Yep: :)

myPoints = [[0,0], [0, 10], [10, 10], [10, 0], [0, 0]];
myPaths = [[1, 2, 3, 4, 5]];

linear_extrude(height=10)
polygon(points=myPoints, paths=myPaths, convexity=10);

thanks so much for the work. Being the OpenScad guy that I am, there's plenty for me to learn. And these will make for good desktop curiosities.

Woot!

Thank you, thank you, thank you. :-D

And yes, arrays would go a long towards making OpenSCAD scripts for stuff like this less... uh... idiosyncratic.

I've been playing with it and it is fast!

Great work and great documentation.

Here are three examples of different mechanisms that can be created with the OpenSCAD script.

theres a slight optical illusion if you stare at that last one long enough...

Top