Introduction: Custom Mechanical Biorhythm Computer, 3D Printed

Update: After posting this, I realized that it's missing the most important part of any instructible! I'll be posting a complete list of parts, complete with STL files for them, in case you want to build one on your own. In the meantime, I've attached the full STL model below, and made it downloadable at both Ponoko and Shapeways. Have fun!

The goal of this project was to automatically generate a mechanical computer.

Furthermore, it should...
    ...compute something useful,
       ...be made to order, and unique to each person,
          ...and emerge from the 3D printer pre-assembled, ready to run.

Sure, um, no problem.

The first major obstacle: Using 3D modeling tools
Let's put it this way: I can build something in a 3D modeling package, just like I can eat my breakfast using only a hammer. I won't starve, but I sure don't want anyone looking over my shoulder while I'm doing it.

I'm a software engineer, but there's no way I'm comfortable enough in a package like Maya or Blender to build a custom computer made of gears.

...still, the process was ultimately successful (you can play with the 3D model here), so the rest of this instructible will be an outline of what was involved.

(See the attached PDF for an interesting short description of the final machine)


Step 1: Problem 1: What Should It Compute?

Here's what I decided the computer should do:
   - At the time it's made, you specify the dates of birth (month, day and year) for two people. That's all.
       (The machine is built specifically for those two people, and can't be changed.)

   - The finished machine will have a calendar display (for 100 years or so), and three pairs of indicator needles.
      -  ...so when you set it to the current date, the needles will show the Biorhythm (intellectual, emotional and physical)
             readings for those two people. So they can know (just for example) when they're in sync physically. Ahem.

What's Biorhythm?
I know about biorhythms because when I was in 7th grade my folks helped me print out computer-generated biorhythm charts as gifts for my teachers. Those charts were amazing, because it was 1981 and a lot of really basic computer stuff was amazing in 1981.

In case you haven't heard about biorhythms, I'll do a quick overview, but you can read about them here:
http://en.wikipedia.org/wiki/Biorhythm

Biorhythms are kind of like astrology. They're interesting and fun, but not actually science.
The idea is that there are 3 cycles which govern how you feel, and they oscillate at different frequencies
  23 days for "physical"
  28 days for "emotional"  (Yeah I know, but I swear I didn't make that one up)
  33 days for "intellectual"

As these go up and down, you supposedly get strong/weak, cheerful/cranky, and smart/dumb.
Like I said, it's fun to share with friends or an SO, but not actually science.

Besides the fun, the reason I decided to do this is that the computer only has to produce three sine waves. That's all. If I can't make a computer that does that, then I've got no business making anything more complex, like an orrery or an encryption device.

So whatever other parts there are, the machine is going to need three special gears for sure (see picture): One with 33 teeth, one with 28 teeth, and one with 23 teeth.

Step 2: Problem 2: Getting Some Help With the Gears

This computer is going to me all mechanical, made of gears, not chips and wires. Fortunately, the instructables user HotSharpToxicis a mechanical engineer. And, she needs software help with her own project, so I've got something to trade. And, she's hot.

After spending a few long lunches talking about bearings, gear ratios, miter angles, and cam shafts, I've got enough of the basics that I can start at least thinking about the problem.

What followed was a whole lot of sketching and math.

I ended up having to invent my own "tree-gear" notation (circles and lines in the notes) to make sense of it all. I won't go into that much here, because I'm not sure it's generally useful. Instead, I'll entertain you with related sketches from my very worn-out notebook.




Step 3: Problem 3: Thumb Tacks and Cardboard

So I've got a "gear tree" on paper. That's not enough to start with, really. Gears take up physical space, and get in each other's way.

In order to lay them out and figure out what goes where, I actually cut out a circle for each gear and spent a day sticking thumbtacks through them in a hundred different configurations.

When I showed HotSharpToxic my favorite layout, she said "Does it have to be flat? It's a 3D printer, after all..."
Wow yikes, she's right. So then I start folding it, and find an arrangement I like waaaay better. It meant writing special C++ code to make angled (mitered) gears, but it was worth it.

Step 4: Non-Problem 4: Writing the Software

Finally, a step I've actually got the skills for.

I work on real-time 3D software a lot, which means I'm used to making things which don't work at first, and then after I've debugged them, still don't work. I'm used to staring at a screen full of text with a single punctuation mark out of place, stopping everything, and unable to spot it, at 3am.

What I needed here was a program which would build and position all of the gears for me automatically, based on the number of teeth and other info I provided. Also, it needs to take in birthdates of the two people, and build the gears specifically to point the needles in the right direction for them. All of that ends up taking a while.

I wrote the software in C++, using a framework called Qt to save time on the standard "buttons and windows" part. (Incidentally, since HotSharpToxic's lipstick thing was going on at the same time, I decided to make one program that does both, to save time.)

For this software to work, I needed a format to store a description of a gear machine.
That way I can change the specification to mess with the machine, instead of the C++ code.
The text-file format I chose is wonky and ugly, but very quickly did the job.

The complete parametric specification for the gears in the machine is here:
(Even if you're not a software engineer, you can probably pick out some parts.
The key is the group of words right after the "expr" section.)


//______________________________________________________________________
// GearMachine.tsu  -  Bio gear machine, version 49b
//
expr, thickness, 0.3
expr, extraThick, (1.0 * thickness)
expr, stackOffset, (1.25 * thickness)
expr, toothSize, 0.30
expr, axleDiameter, 0.5

// Gear id, numTeeth, toothSize, thickness, axleDiameter, addAxle, u1, u2, v1, v2

image, gears/plainGear1.png

expr, baseDrop, -0.5
expr, timeAngle, 0.0
expr, emoAngle, 220.0
expr, emoArch1Angle, (emoAngle - 60.0)
expr, emoArch2Angle, (emoAngle + 60.0)

// real gears are below
//    name          teeth  toothSize  thickness  axleDiameter  verticalOff   parent         connect angle   tilt backWidth backOffset stackOffCenter fixArrowLen fixArrowAngle fixArrowOffset  topAxleExtend  bottomAxleExtend
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
gear, rootGear89,      89, toothSize, extraThick,axleDiameter, 0.0,          none,            stack,  0.0,   0.0,    1.00,    -1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, rootGear79,      79, toothSize, extraThick,axleDiameter, stackOffset,   rootGear89,      stack,  0.0,   0.0,    0.00,     0.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0

gear, 3monthStandoff,  18, toothSize, thickness, axleDiameter, 0.0,          rootGear79,      link,   timeAngle,  0.0,    1.0,      -1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, 3monthStandoff2,  18, toothSize, thickness, axleDiameter, 4.5,          3monthStandoff,   stack,   0.0,  0.0,    0.00,      0.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, 3months55,         55, toothSize, thickness, axleDiameter, 0.0,          3monthStandoff2,  link,   180.0,  0.0,    0.00,    -1.0,      0.0,         10.0,           0.0,          0.3,           0.3,           0.0
//gear, 3months55,       55, toothSize, thickness, axleDiameter, 0.0,          rootGear79,      link,   0.0, 110.0,    0.00,    -1.0,      0.0,         10.0,           0.0,          0.3,           0.3,           0.0
gear, 3months10,       10, toothSize, thickness, axleDiameter, (-1.0*stackOffset),  3months55,       stack,  0.0,   0.0,    2.50,    -1.0,      0.0,           0.0,           0.0,          0.0,           0.0,           0.0
gear, monthsToYears30, 30, toothSize, thickness, axleDiameter, 0.0,          3months10,       link, -130.0,   0.0,    0.00,     0.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, monthsToYears10, 10, toothSize, thickness, axleDiameter, (-1.5*stackOffset),  monthsToYears30, stack,  0.0,   0.0,    2.50,    -1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, 3years40,        40, toothSize, thickness, axleDiameter, 0.0,          monthsToYears10, link,  90.0,   0.0,    0.00,     0.0,      0.0,          7.0,                   0.0,       0.3,           0.3,           0.0

gear, 3years10,        10, toothSize, thickness, axleDiameter, (-3.0*stackOffset),  3years40,        stack,  0.0,   0.0,    2.50,    -1.0,      0.0,          0.0,           0.0,           0.0,            0.0,           0.0
gear, yearsToCentury60, 60, toothSize, thickness, axleDiameter, 0.0,          3years10,         link,  123.0,   0.0,    0.00,     0.0,      0.0,          0.0,           0.0,           0.0,            0.0,           0.0
gear, yearsToCentury10,  10, toothSize, thickness, axleDiameter, (-2.0*stackOffset),  yearsToCentury60,stack,  0.0,   0.0,    2.50,    -1.0,      0.0,          0.0,           0.0,           0.0,            0.0,           0.0
gear, century60,         60, toothSize, thickness, axleDiameter, 0.0,          yearsToCentury10, link,  180.0,   0.0,    1.00,     -1.0,      0.0,          0.0,           0.0,           0.0,            0.0,           0.0

gear, emoStandoff,     10, toothSize, thickness, axleDiameter, 0.0,          rootGear89,      link, emoAngle,  68.0,    1.00,   -1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, emotional19,     19, toothSize, thickness, axleDiameter, 0.0,          emoStandoff,      link,  0.0,  68.0,    1.50,     1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
//gear, emotional19,     19, toothSize, thickness, axleDiameter, 0.0,          rootGear89,      link, 120.0, 120.0,    1.50,     1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, emotional28,     28, toothSize, thickness, axleDiameter, -stackOffset, emotional19,     stack,  0.0,   0.0,    0.00,     0.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, physical23,      23, toothSize, thickness, axleDiameter, 0.0,          emotional28,     link, -90.0,   0.0,    1.50,     1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, intellectual33,  33, toothSize, thickness, axleDiameter, 0.0,          emotional28,     link,  90.0,   0.0,    1.50,     1.0,      0.0,           0.0,           0.0,           0.0,           0.0,           0.0
gear, [emotionalArrow],     10, toothSize, thickness, axleDiameter, -0.21, emotional28,         link,   0.0,   0.0,    1.50,     -0.1,      0.0,           0.0,           0.0,           0.0,           0.0,           0.6
gear, [physicalArrow],     10, toothSize, thickness, axleDiameter, 0.0, physical23,           link,  90.0,   0.0,    1.50,     -0.1,      0.0,           0.0,           0.0,           0.0,           0.0,           0.6
gear, [intellectualArrow],     10, toothSize, thickness, axleDiameter, 0.0, intellectual33,   link, -90.0,   0.0,    1.50,     -0.1,      0.0,           0.0,           0.0,           0.0,           0.0,           0.6
_________________________________________________________________________________

Step 5: Problem 5: Support Structure

So I'm all excited, because I figure I'm done, when suddenly I remember that it's not actually a machine yet.
It's a pile of gears, magically suspended in the air. Uh oh.

I need a support structure. Not only that, but it has to be strong and rigid, or the gears will skip, or fall off. And since 3D printing companies charge based on the amount of material you use, the structures need to be thin, or it'll cost a fortune. Yikes.

Time to chat with the cute mechanical engineer again.

She immediately draws a parabola (like the St. Louis Arch), holding one gear in place above another. That'll work, but I need to make the software generate them automatically, and make sure they don't intersect other gears.
(I have to say, the result I ended up with was so crazy strong and light that I owe her dinner for sure.)

I wrote some more C++ code (I actually used asymmetric quarter-ellipses instead of parabolas because it took less time to code), and then here's what I added to that ugly cryptic gear-data file:

//__________________________________________________________
//////////////////////////////////// Arches
//    name  numFacets radialThickness axialThickness topgear      axial radial angle bottomgear   axial radial   angle  midgear     axial radial angle
arch, rootABArch,  256,     0.2,           0.2,     rootGear89,  -0.3,  0.0,   0.0, rootGear89,    -0.31,   1.2,  0, none,    0.0,   0.0,    0.0
arch, rootABBrch,  256,     0.2,           0.2,     rootGear89,  -0.3,  0.0,   0.0, rootGear89,    -0.31,   1.2,  120, none,    0.0,   0.0,    0.0
arch, rootABCrch,  256,     0.2,           0.2,     rootGear89,  -0.3,  0.0,   0.0, rootGear89,    -0.31,   1.2,  240, none,    0.0,   0.0,    0.0

arch, timeStandArchA,  256,     0.3,           0.2,     3monthStandoff,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle+5), none,    0.0,   0.0,    0.0
arch, timeStandArchB,  256,     0.3,           0.2,     3monthStandoff,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle-5), none,    0.0,   0.0,    0.0

arch, emoStandArchA,  256,     0.3,           0.2,     emoStandoff,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoAngle+5), none,    0.0,   0.0,    0.0
arch, emoStandArchB,  256,     0.3,           0.2,     emoStandoff,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoAngle-5), none,    0.0,   0.0,    0.0
arch, arch1,  256,     0.3,           0.2,     physical23,  0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoArch1Angle+10), none,    0.0,   0.0,    0.0
arch, arch2,  256,     0.3,           0.2,     emotional19,  0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoArch1Angle+5), none,    0.0,   0.0,    0.0
arch, arch3,  256,     0.3,           0.2,     intellectual33,  0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  emoArch1Angle, none,    0.0,   0.0,    0.0
//arch, arch3,  256,     0.3,           0.2,     emoStandoff,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoAngle - 10.0), none,    0.0,   0.0,    0.0
arch, arch4,  256,     0.3,           0.2,     physical23,  0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoArch2Angle+10), none,    0.0,   0.0,    0.0
arch, arch5,  256,     0.3,           0.2,     emotional19,  0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  emoArch2Angle, none,    0.0,   0.0,    0.0
arch, arch6,  256,     0.3,           0.2,     intellectual33,  0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoArch2Angle+5), none,    0.0,   0.0,    0.0
//arch, arch6,  256,     0.3,           0.2,     emoStandoff,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoAngle + 10.0), none,    0.0,   0.0,    0.0
arch, archInt,  256,     0.3,           0.2,     intellectual33,  0.5,  0.0,   0.0, [intellectualArrow],    0.0,   0.0,  0.0, none,    0.0,   0.0,    0.0
arch, archEmo,  256,     0.3,           0.2,     [emotionalArrow],  0.0,  0.0,   0.0, yearsToCentury60,    0.4,   0.0,  0.0, none,    0.0,   0.0,    0.0
arch, archPhy,  256,     0.3,           0.2,     physical23,  0.5,  0.0,   0.0, [physicalArrow],    0.0,   0.4,  0.0, none,    0.0,   0.0,    0.0
arch, archInt,  256,     0.3,           0.2,     intellectual33,  0.5,  0.0,   0.0, [emotionalArrow],    0.0,   0.0,  0.0, none,    0.0,   0.0,    0.0
arch, archPhy,  256,     0.3,           0.2,     physical23,  0.5,  0.0,   0.0, [emotionalArrow],    0.0,   0.4,  0.0, none,    0.0,   0.0,    0.0

arch, centA,  256,     0.3,           0.2,     century60,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle+60), none,    0.0,   0.0,    0.0
arch, centB,  256,     0.3,           0.2,     century60,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoArch1Angle+15), none,    0.0,   0.0,    0.0
arch, centC,  256,     0.3,           0.2,     century60,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle - 35), none,    0.0,   0.0,    0.0
arch, yearA,  256,     0.3,           0.2,     yearsToCentury10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle+55), none,    0.0,   0.0,    0.0
arch, yearB,  256,     0.3,           0.2,     yearsToCentury10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (emoArch1Angle-5), none,    0.0,   0.0,    0.0
arch, yearC,  256,     0.3,           0.2,     yearsToCentury10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle-50), none,    0.0,   0.0,    0.0
arch, m2yA,  256,     0.3,           0.2,     monthsToYears10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle+25), none,    0.0,   0.0,    0.0
arch, m2yB,  256,     0.3,           0.2,     monthsToYears10,  -0.4,  0.0,   0.0, yearsToCentury60,     0.4,   0.0,  0.0, none,    0.0,   0.0,    0.0
arch, m2yC,  256,     0.3,           0.2,     monthsToYears10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle-40), none,    0.0,   0.0,    0.0
arch, monthA,  256,     0.3,           0.2,     3months10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle+20), none,    0.0,   0.0,    0.0
arch, monthB,  256,     0.3,           0.2,     3months10,  -0.4,  0.0,   0.0, yearsToCentury60,    0.4,   0.0,  0.0, none,    0.0,   0.0,    0.0
arch, monthC,  256,     0.3,           0.2,     3months10,  -0.4,  0.0,   0.0, rootGear89,    baseDrop,   1.2,  (timeAngle-45), none,    0.0,   0.0,    0.0
___________________________________________________________________________





Step 6: Problem 6: Axles and 3D Printing

When you're trying to 3D print an object pre-assembled, wheels, gears, and axles are a big problem.

Here's the issue:
- You want the fitting to be tight, so it turns smoothly without wobbling
- ...but if it's too tight, the printer will fuse them together, nothing will move, and you'll just have a really expensive doorstop.

My solution to this problem was to write special C++ code for the axles, to "ruffle" them.
By making them shaped like little daisies (the macho geek term is sinusoidally perturbed, I guess), you can make the gear hubs fit more tightly on the axles, and if they do fuse they'll probably un-stick easily.

An added benefit with this shape is that they kind of act like cheeseball ball-bearings. Kind of.

In the final version of the model, I loosened the axles (and gear teeth) up a bit, providing extra space, because I'm a big chicken and I really didn't want the model to come back all fused together. After all, it's going to be $120 or so to try it, and there are 21 gears in the thing.

Step 7: Problem 7: Upload, Upload, Upload.

When you talk to the awesome folks at Shapeways, please be nice to them.
In addition to running an innovative company, they have to deal with crazy people trying to build hilariously complicated machines, who actually have no idea what they're doing and are making it all up as they go. I'll bet it's not just me.

So when I said "Aha! I'm ready to print!" and uploaded my file, their validation robot kicked it back right away. The error was pretty cryptic, and basically translated to the computer version of "You've got to be kidding me."

This is a problem any time you try to 3D print something complex. It's very (very) hard to figure out why it's getting kicked back. Is it one of the 706 gear teeth? Which one?

The best way to solve this is to remove half the model and try it again. Software engineers call that a binary search. I stripped out half the model, and then half again, until I was finally down to a single gear. That's when I realized there was a microscopic flaw in the structure of the gears (a vertex indexing error, causing iris-pattern overlap).

After that, I only had to try uploading another 30 times or so before I finally got it right.

Step 8: Finale: Getting the Model

A few days later, Shapeways printed the model for me, but something went wrong, and it failed during the printing.

That's a huge problem, because there's no way I can get information about what went wrong. It's such a complex bunch of parts, it could have been just about anything. Shapeways gave me credit for the full price (I love Shapeways credit, and love using it.)

I happen to live near a Ponoko location (Oakland), and so I decided to give them a try. Maybe I could print it there, and then go see what went wrong. Like the Shapeways folks, they deal with crazy people all the time. When I uploaded my model, I was contacted right away by a friendly person who said "That's not going to work..." but before I could protest, he said "...because you picked the wrong material. Here, try this."

Four days later, I had the model in my hands, and it works!

Sure, the axles are a bit too loose (because of the chicken in Step 6), and there are about 15 other things I'll want to change for prototype #2, but holy cow does it feel good to hold the result of all of this in my hands, and spin the gears.

Without both Ponoko and Shapeways, and especially HotSharpToxic, it wouldn't have happened. Thanks.
(you can play with the 3D model here)

Make It Real Challenge

Participated in the
Make It Real Challenge