Laser Cutter
This week I used a laser cutter to build a general-purpose cardboard construction set. I built 3D models in Antimony, exported them as PNGs, and laid them out in CorelDRAW for sending to the laser. Here's something I built with my construction set.
To do this, I started with some code Neil wrote specifying square building blocks with various joint types. It generated this output:
Neil's code was designed without a larger system in mind, so many components were hardcoded and not easy to reuse. I refactored his code to decouple each joint from whatever it formed a joint in. Joints get built at position a0 and get stored in a ShapeList node called slots. Then anyone who wants one can access it with slots.shape2 (or whatever its list index is), moving its origin to the desired point p by translating by p-a0.
Having modularized the joint definitions, it was time to test the sizing parameters and get something into cardboard. First I wanted to know how wide the joints should be. I made five copies of the simple rectangle slot and gave each one a slightly different width. Widths centered on 0.167", the width of the cardboard (measured by caliper). Then I inserted the joints into a wide rectangle. I cut two copies with the laser (I'll explain this process in a second) and found that for the laser-cardboard combination I was using, 0.157" forms a snug fit. Values +/-0.01" from this were too loose or couldn't be assembled. I could always go back later to test finer refinements to the width, but this was good enough for now.
Now I wanted to try Neil's five different joints. Using the same pattern, I put one joint each into a rectangular strip and printed two copies. This constituted the most general case of cutting on the laser cutter because it had internal cuts, not just an outline, so let me now explain the process of getting my Antimony file into the laser cutter.
First, whatever 2D Antimony shape I want to cut gets extruded into 3D. Exporting this as a heightmap generates a corresponding black and white image. I open a new CorelDRAW file with the laser cutter's dimensions (32"x18" for this one). Dragging the PNG into CorelDRAW preserves the image size, but the white-on-black 2D shape needs to be converted to a 1D outline.
Select Trace Bitmap > Outline Trace > High Quality Image. By default this traces the shape outline and ignores internal holes. Therefore, select Specify Color and choose the color black. Set smoothing to zero and check "Remove color from entire image". Hit Ok. Set the trace width to Hairline and delete the original PNG. Do this for each image you want to cut, duplicate traces you want multiple copies of, and arrange your traces in the layout you'd like to have them cut in. Print the image, and in Preferences make sure the color black is selected and is set to VECT and MANUAL. I found that the laser settings 100% power, 8% speed and 400 ppi worked well for cuts; 6% and 500 ppi also worked but singed the cardboard more than necessary and was slower. Applying these settings and clicking print sends them to the laser cutter.
Make sure the laser cutter is turned on, and switch on the exhaust and the hood. Check that the laser head is set to the right height. (There's a dongle with a notch in it that describes how high the laser bracket should be above the material surface; to adjust the head, press Z, then use the up and down keys in combination with the select key for selecting precision.) Position a piece of cardboard in the cutting bed, tape down the edges for stability, and close the lid. You have to nudge the lid a bit for the machine to detect that it's closed. At this point, turn on the tank of inert gas and hit select to start cutting.
When it's done, turn off the gas. Open the laser cutter lid and let it air out a bit, then remove your pieces and throw out any cardboard scraps. (You don't want to leave an uneven surface for the next person.) One tip for pulling out your pieces is to lift them out with masking tape.
This was supposed to let me test the five joint types, but the first cut was a flop - I'd determined the slot width should be 0.157", but then I set it to 0.1". Whoops. So I did a second cut. The triangular mouthed slot made them easier to fit together, but the mouth was way wider than necessary (100% gain over the slot width). I parameterized its width in my var list and reduced it to 50% gain. The other three joints were dysfunctional. For now I put that concern aside - it might be fun to return to, but I have a good enough joint in the triangular-mouthed slot.
Now I wanted construction pieces other than squares. I started with regular polygons with n sides. An n-gon can be made from n identical triangles with a shared center pieced together like pizza slices. (Draw a line from each vertex to the center; these divide it into identical isosceles triangles.) The inner angle of each triangle is 2 pi / n, so for a fixed side width the shortest radius to the edge is width / 2 tan(pi / n). The radius to a corner is width / 2 sin(pi / n). So I added numSides as an input in my var list and calculated radiusToEdge and radiusToCorner as two other vars. I set numSides to 4 for starters so I could compare my refactoring progress to Neil's original square tiles. This helped me catch multiple mistakes. I changed the slot rectangle's starting x position from -var.width/2 to -radiusToEdge and made similar substitutions in the other joints. I built a triangle in terms of numSides and removed the slot from it, the first quarter of a square tile. Varying n varies the slotted triangle correctly. Multiplying the triangles with Atimony's polar array completes the polygon. Swapping the joint type for more advanced slots works as it should.
Up to this point all my building blocks were rigid, and I wanted my kit to have flexible components as well. Or, well, mostly I just wanted to try making flexures, and this was a good excuse. I built the base flexure unit out of rectangles and used Antimony's 2D array to tessellate it n times lengthwise.
When I cut the flexures, little flames kept showing up each time the laser went over a slit a second time. I figured this was due to going over it twice (no way to make 1D lines in Antimony, so the slits are thin rectangles), but then my friend Nils pointed out that I didn't have the nitrogen gas turned on. Whoops! So if you see flames, check that you turned on the gas. (Unless the flames are dangerously big, of course - then you should immediately turn off the laser cutter!)
The flexures came out nicely. I'd done 0.01" slits and tried beam widths of 0.06, 0.08, 0.10, 0.12, and 0.14. (The laser's kerf meant that the actual gaps were larger and the beams smaller than these numbers: the 0.06" beams were actually 0.045" with 0.025" gaps.) They all had 1.5" heights, same as the construction blocks, and I gave each piece six flexure cycles. Cutting them took 3.5 minutes. For each piece I measured its maximum curvature out-of-plane, the maximum arc-length (a curvature proxy) in-plane, and, as best I could, the maximum axial twisting.
beam width | 0.06 | 0.08 | 0.10 | 0.12 | 0.14 | err | (inches, pre-kerf) |
---|---|---|---|---|---|---|---|
out-of-plane | 0.5 | 1 | 2 | 3 | 5.5 | 0.125 | (arc radius in inches) |
in-plane | 10 | 5 | - | - | - | 20% | (arc length in degrees) |
axial twisting | 10 | - | - | - | - | 10 | (arc length in degrees) |
The limitation on in-plane deformation comes from the beams running into each other at the compressed end, so increasing the gap width makes them bend farther. I tried a few more versions:
more sizes with gap width fixed at 0.01"
beam width | 0.02 | 0.03 | 0.07 | err | (inches, pre-kerf) |
---|---|---|---|---|---|
out-of-plane | 3/16 | 3/8 | 0.75 | 0.125 | (arc radius in inches) |
in-plane | 45 | 20 | 12 | 20% | (arc length in degrees) |
axial twisting | 30 | 15 | - | 10 | (arc length in degrees) |
keeping beam width fixed at 0.06"
beam width | 0.02 | 0.03 | 0.04 | 0.05 | err | (inches, pre-kerf) |
---|---|---|---|---|---|---|
out-of-plane | 3/8 | 3/8 | 0.25 | 0.125 | 0.125 | (arc radius in inches) |
in-plane | 15 | 17 | 18 | 20 | 20% | (arc length in degrees) |
axial twisting | 15 | 20 | 25 | 30 | 10 | (arc length in degrees) |
Generally, I'm pretty happy with beam widths 0.05 and 0.06 sizes using gaps at 0.01.
Time to incorporate these into construction blocks! I made flexible connectors with two types of end effectors, one square-aligned and the other circular. The circular ends have the advantage of allowing joints at arbitrary angles, though I stuck with 8-gon angles for these cuts since that seems satisfactorily general. While I was at it, I made some rigid circle pieces, too, one for each of n = {3, 4, 5, 6, 7, 8, 10} joints.
There's more I'd like to do, but I'm out of time for now. If you'd like, here's my Antimony script for these components. I've also written up some Antimony tips from my experiences so far, and I've posted the code for an as-yet-undocumented Antimony reproduction of Dan Chen's Interlocking Circle pressfits.