For this week I wanted to make a grid of gadgets that a gear moves through and does logic. (Originally the plan was to make a divider by 10 and actuate a segment display based on that, but time ran out)

Scale Down

First, I designed some small 2-inch gadgets, starting with the wire, right turn, and left turn (and the turns aren’t symmetric). The gear diameter was 0.375 in, and it had 12 teeth. A rack that went across the gadget had 24 teeth. Since the gadget would be in 2 pieces, I needed a structure to hold the pieces together. The original design was done in FreeCAD.

Wire gadget design
The design of the wire gadget. There is a structure that forms a square and holds the two pieces of the gadget together. Notice the absence of cutouts in corners.
Small gadgets
The wire, left turn, and right turn gadgets. Notice how beautiful and rigid they are. It would be a shame if...

Getting the racks for the curves was tricky. I really wanted gears with a non-integer number of teeth (and now that I think of it, that would have been incorrect, given that I needed to do a 90° transition from the middle of a tooth to the middle of another tooth), but that wasn’t happening, so I chose the closest integers I could find. Apparently I chose one too big for the left turn. Internal gears are unforgiving.

I also needed to make a gear that served as the player. After some experimenting, the gear was made to have curved surfaces on the interface with the gadget track so that it can transition smoothly between gadgets. This was 3D printed.

Small gear
The small gear.

However, a BIG problem showed up.

Joint Hell

There are slot joints and hole joints, and they both need to have just the right fit. Too loose and the gadget will come apart. Too tight and you can’t put it together in the first place. Since the gadget is laser cut, there’s also the variable kerf of the laser cutter to account for, and the fact that the bed isn’t flat, and the fact that the acrylic isn’t flat, the edge of the cut being a little rough, and the shape of a laser cut being slanted (wider on the top and narrower on the bottom). All this variation adds up to more than the distance between “too loose” and “too tight” for a joint, even when attempting to account for kerf. I have had many, many pieces fit too loosely or break when trying to fit them. And that’s after doing a joint fit test due to the variation mentioned above.

The parameters I found that worked initially were -0.08 mm of slot joint width expansion (so they contract) and 0.125 mm of hole joint hole width expansion. This was done on the bigger laser cutter in EDS with 100% power, 5.1% speed, and 1000 freq, with a kerf of 0.26mm. And they were pretty nice, if not a little tight. Except that I didn’t add corner cutouts (“dogbones”) so the corners were rounded by half the kerf and I was effectively trying to fit a square peg into a round hole for the hole joints.

Cutting Corners

So I added the dogbones. But first, I didn’t like how bloated the FreeCAD design was getting (with names like Extrude547) even when I tried to be as parametric as possible. So I moved it to Inkscape and designed the items in a rather interesting way. I used lines to indicate things like wire cutouts and fingers. (I also switched from a square holder to an X holder design. This was a mistake in terms of rigidity. However, it saved time and material in a time when time was precious.)

Inkscape design example
An example of a design made in Inkscape. This is a scaled-up version.
  • Black: outline
  • Green: wire cutout
  • Blue: hole joint hole
  • Yellow: other hole
  • Dark blue: finger
  • Pink: scaffolding cutout
  • Light blue: extender (needed separately because of dogbone positioning implied by fingers)
  • Red: slot joint
  • Cyan: manual dogbone (unnecessary, but whatever)
  • Purple: engraving (technically super-fast cutting)

I made a script using the Simple Inkscape Scripting extension to convert this into the actual shapes that would be cut. Except that scripting is limited, so I had some manual steps at the end:

  • Select all light blue, dark blue, red, and green lines and convert strokes to paths
  • Select all black, dark blue, and light blue shapes and union them
  • Select all other shapes except cyan ones (the now actually circular dogbones) and purple ones (the engraving) and union them
  • Difference the results of the above two
  • Set stroke to red and hairline (to make it a vector operation), including the dogbones
  • Offset the main shapes by half the kerf and the dogbones by negative half the kerf

Here’s the script:

from inkex.transforms import Vector2d, Transform

side_length = 4*inch
wire_thickness = 0.25*inch
sheet_thickness = 3*mm
hole_expansion = 0.04*mm
slot_expansion = -0.12*mm
boolean_clearance = 0.02*mm
dogbone_radius = 0.375*mm # must be at least laser cutter kerf / 2

def normalized(vec):
    return vec / vec.length

def extend(line, amount: float, end: bool):
    path = line._inkscape_obj.path.to_absolute().to_non_shorthand()
    points = list(path.end_points)
    first = 1 if end else 0
    path[first] = path[first].translate(normalized(points[1 - first] - points[first]) * -amount)
    line._inkscape_obj.set("d", path)

def add_line_dogbones(line, end: bool):
    thickness = line.style()["stroke_width"]
    points = list(line._inkscape_obj.path.end_points)
    if not end:
        points = points[::-1]
    dir = normalized(points[1] - points[0])
    perp = Transform("rotate(90)").apply_to_point(dir)
    scaled_perp = perp * thickness / 2
    extra_dogbones.append([points[1] + scaled_perp, -dir, -perp if end else perp])
    extra_dogbones.append([points[1] - scaled_perp, -dir, perp if end else -perp])

shapes = selected_shapes()
extra_dogbones = []

# Holes
holes = [s for s in shapes if s.style()["fill"] in ["#0000ff", "#ff8000"]]
for hole in holes:
    if hole.style()["fill"] != "#ff8000":
        hole.scale((sheet_thickness + hole_expansion) / sheet_thickness, "c", first=True)
    points = list(hole._inkscape_obj.path.transform(hole._inkscape_obj.composed_transform()).end_points)
    points.append(points[1])
    for p0, p1, p2 in zip(points, points[1:], points[2:]):
        extra_dogbones.append([p1, p0 - p1, p2 - p1])

# Fingers
fingers = [s for s in shapes if s.style()["stroke"] == "#000080"]
for finger in fingers:
    if finger.style()["stroke_dasharray"] != "none":
        points = list(finger._inkscape_obj.path.end_points)
        extend(finger, (points[1] - points[0]).length * (-1 + 3*mm / (0.125*inch)), True)
    finger.style(stroke_dasharray="none", marker_end="none")
    extend(finger, boolean_clearance, False)
    add_line_dogbones(finger, False)

# Slots
slots = [s for s in shapes if s.style()["stroke"] in ["#ff0000", "#ff8000"]]
for slot in slots:
    if slot.style()["stroke"] != "#ff8000":
        slot.style(stroke_width = slot.style()["stroke_width"] + slot_expansion)
    slot.style(marker_end="none")
    extend(slot, boolean_clearance, False)
    add_line_dogbones(slot, True)

# Dogbones
def add_dogbone(point, dir0, dir1):
    bisector = normalized(dir0 + dir1)
    pos = point + bisector * dogbone_radius
    dogbone = circle(pos, dogbone_radius)
    dogbone.style(fill="none", stroke="#00ffff", stroke_width=0.01*inch)

corners = [s for s in shapes if s.style()["fill"] == "#00ffff"]
for corner in corners:
    points = list(corner._inkscape_obj.path.end_points)
    add_dogbone(points[1], points[0] - points[1], points[2] - points[1])
    corner.remove()

for extra in extra_dogbones:
    add_dogbone(*extra)

This would be simpler if I could include the dogbones in the difference operation, but unfortunately Inkscape is inaccurate with them and tends to produce results like this:

Inaccurate dogbone subtraction
An inaccurate dogbone subtraction that often shows up in Inkscape. Yellow = outline, cyan = dogbone, red = result.

So the dogbones have to be cut separately.

Joint Hell 2

…and my luck ran out with the joints. To be fair, I switched laser cutters to the big one in Metropolis for a time. With the same parameters, after accounting for its kerf, the joints were too loose. Which was to be expected, since now there are dogbones, but it’s still annoying. More joint testing. Ugh.

Frame Grid

I mentioned scaffolding briefly. This is what the frame grid is for. It’s a grid made of 12 edges crossing 12 edges, resulting in an 11×11 array of cells. This was also designed in Inkscape using the same design method.

Frame design
The frame design, made in Inkscape

There are stubs (marked in dark blue) on one type of edge. These stubs would hold little towers for scaffolding. I made them 1/8” tall, which was a mistake in retrospect, since it gave the towers a little too much freedom to rotate.

We had a 4’×4’ machine and 4’×4’ OSB boards. However, I couldn’t fit all 24 edges in that size, so I had to use 2 boards. One for 16 of the edges, and the other for the remaining 8. Then came the CAM. I made a fat contour toolpath with a 3/8” flat end mill and a precise contour toolpath (for dealing with dogbones) with a 1/8” flat end mill. The CAM is here

Frame CAM
The CAM after both contours. The toolpath shown is the precise contour toolpath, made with the 1/8" tool.

Then came machining. As it turns out, we were supposed to use a 1/4” flat end mill for the corners and I used a 1/8” flat end mill because there was a typo in Anthony’s issue. This means double the number of depth passes taking a lot of time. The job for 8 edges took about 45 minutes. The first time the job was ran, the machine squealed, which we suspect was due to some especially hard OSB. We tried using a downcut bit instead of a compression bit, but it still made that sound. I was going to run the 16-edge job after this, but simply put, time was running out, so I decided to just do another 8-edge job and do the rest later (which never happened, due to time and joint issues (not with the frame, but with gadgets)).

After that, the towers. I was going to CNC mill them but after doing so on 49 of them and being very disappointed by the fact that they won’t fit (and this is after testing for fit beforehand. Wow, joints are annoying), so I laser cut them instead. The design, of course, was made in Inkscape, using the same method.

Frame tower design
The frame tower design, made in Inkscape
Frame with 16 towers
The frame, with 16 edges put together and 16 towers.

Scale Up

The frame is made of 4”×4” cells, so it’s time to scale up the gadgets to 4”. And the player gear. After another struggle with joints, this is what the result looks like:

Big gadget design
The designs of the (big) wire, left turn, right turn, merge, and switch gadgets. This also includes a joint test, and a design for the big gear since the 3D printer was occupied at the time.
Big trivial gadgets
The wire, left turn, and right turn gadgets. Unfortunately, they are not as rigid due to a X holder being used instead of a square holder.
The merge gadget. Two paths merge into one.
The switch gadget. The player can flip the switch to make the gear go the other way.
Gadgets on frame
The gadgets on the frame, held up and aligned by the towers.

The merge and switch gadgets are not trivial. They require some mechanism to make sure the gear stays on (t)rack. In the case of the switch, a switching mechanism is needed.

In the merge gadget, there’s a part that makes the gear stay on (t)rack if it’s making a left turn. If it’s going straight, that part is pushed out of the way and pulled back by a rubber band.

In the switch gadget, there’s a part that the player can toggle one way or another, and it controls which (t)rack the gear ends up on. A rubber band is placed such that the two positions are both low-energy states and the intermediate area is a high-energy state. (In practice, the halfway point is stable, probably because of friction.)