cadloop pen holes, two rounds models/spirograph.scad · one file

the report

The spirograph disks or objects that the pen will go into need to be refined. When I print them they are too narrow for a pen to go through. I think the original spirograph had a countersunk shape around each pen-hole so it was easier to draw with. Richard, first report

Two faults named in one sentence: the hole is too small, and its top edge is a square-cut rim a pen has to be aimed into rather than dropped into. The model had them as plain 2.4 mm circles cut straight through a 4 mm plate.

as printed Cross-section of a pen hole: a plain straight bore with square top and bottom edges through a 4 mm plate
Section through hole 1 of the 36T wheel. 2.4 mm straight through 4 mm, square edges top and bottom.

Every section on this page is projection(cut = true) through the plane y = 0, which passes exactly through the centre of pen hole 1. The notches along the top edge are the debossed hole number, cut by the same plane. Nothing here is drawn by hand.

What follows is two rounds, because the first fixed a real fault and still left the tool unusable. That second report is step six.

the bore

A hole modelled at 2.4 mm does not print at 2.4 mm. The perimeters are laid down on the inside of the path and squash inward, so a small hole always comes out undersize. 2.4 was already at the edge; the print pushed it over.

/* [Wheels] */
-pen_hole_d      = 2.4;   // suits a 0.5 to 0.7 mm gel pen. Measure yours
+pen_hole_d      = 3.0;   // bore. 2.4 measured too tight once printed. Measure yours

This is the calibration knob, and everything downstream derives from it: how far the outermost hole sits from the rim (pen_r_max), how many holes a wheel gets (pen_count), and the spacing rule in step five. Change this one number and the rest re-derives. Nothing is hard-coded to it.

Worth saying plainly: 3.0 mm was an estimate for a gel pen after shrinkage, not a measurement. It turned out not to be the binding constraint at all.

the funnel

The second fault named in the report. A shop-bought spirograph countersinks every hole so the pen finds it without aiming and can lean without its shoulder catching the rim. The old model cut a flat circle out of a 2D outline before extruding it, which cannot express a funnel at all, so the hole became a 3D cut.

// A straight bore with a funnel around the top, the way a shop-bought
// spirograph is countersunk: the pen tip drops in instead of being aimed,
// and it can lean without the printed rim catching on its shoulder.
// Cut in 3D, so every wheel subtracts this rather than a flat circle.
module pen_bore() {
    translate([0, 0, -0.5])
        cylinder(d = pen_hole_d, h = wheel_thickness + 1, $fn = 24);
    translate([0, 0, wheel_thickness - pen_cs_depth])
        cylinder(d1 = pen_hole_d, d2 = pen_hole_d + 2 * pen_cs_rim,
                 h = pen_cs_depth + 0.01, $fn = 24);
}
before Straight 2.4 mm bore with a square top edge
2.4 mm, square rim.
round one 3.0 mm bore with a cone opening out at the top face of a 4 mm plate
3.0 mm opening to 4.0 mm across the top 1.0 mm. Plate still 4 mm.

One module, subtracted by both the circular wheels and the three shapes. The old code wrote the hole geometry out twice, once in pen_spiral() and once inline in nc_wheel(), so a fix to one would have left the other wrong. That is why the diff deletes as well as adds.

what it broke

A wider hole with a funnel round it needs more room than a narrow one. On the eleven circular wheels there was room to spare. On the ellipse and the trefoil there was not, and this part of the job was not in the request.

The three non-circular wheels carry hand-generated hole tables laid out on a 2.5333 module grid, which at module 1.5 puts hole centres 3.8 mm apart. A 3.0 mm bore with a 4.0 mm funnel and two perimeters of wall between neighbours needs 4.8 mm. At 3.8 the funnels merge into a groove — and a pen that can slide from one hole to the next does not merely look wrong, it ruins the drawing.

before Ellipse wheel with twenty pen holes packed close together, their numbers overlapping
ellipse, 20 holes at 3.8 mm centres. The numbers collide too, which was the visible symptom of the same crowding.
after Ellipse wheel with ten countersunk pen holes, evenly spaced, numbers legible
ellipse, 10 holes at 7.6 mm centres, countersunk. Both ends of each long ray kept.
ellipse20 → 10 holes
trefoil14 → 8 holes
egg — already 4.98 mm apart8 → 8 holes
eleven circular wheelsunchanged

The spacings those tables offer are multiples of 3.8 mm, so it is all or every other; no arrangement keeps 20 holes and fits a funnel. Fewer usable holes beat more holes the pen cannot sit in.

the thinning

Rather than hand-edit three generated tables, the model drops the crowding itself. It walks each table backwards and keeps a hole only when it clears everything kept so far.

function pen_pitch_min() = pen_hole_d + 2 * pen_cs_rim + 0.8;

function crowded(h, kept) =
    len([ for (k = kept)
            if (gear_module * norm([k[0] - h[0], k[1] - h[1]]) < pen_pitch_min())
                1 ]) > 0;

function thin(hs, i = 0, kept = []) =
    i >= len(hs) ? kept
                 : thin(hs, i + 1,
                        crowded(hs[i], kept) ? kept : concat(kept, [hs[i]]));

function nc_holes(sh) = rev(thin(rev(sh[6])));

Backwards matters. Each ray in those tables is listed inner to outer, and the outermost hole draws the widest figure, so working from the end of the list is what saves it. The result is reversed back so the numbering still counts outward. The threshold is derived, not typed: bore + flare + 0.8 mm of wall, where 0.8 is two perimeters at a 0.4 mm nozzle.

Because it is derived it undoes itself. Raise gear_module to 2.0 and the same tables come out at 5.07 mm centres, above the threshold, and every dropped hole returns with no edit.

still not right

I still can't get the pen to touch the paper comfortably. The countersink isn't sufficient and making it wider will reduce the space we have for pen holes on the shapes. Richard, second report

Round one widened the hole and relieved its rim, and the pen still would not reach the paper. Hole diameter was never the binding constraint. Plate thickness was.

A pen is a cone. For the nib to touch paper it has to pass the whole plate, so what must clear the bore is not the tip but the pen's own diameter one plate-thickness back from the nib. At 4 mm back most gel pens are already into the barrel taper and wider than 3 mm, so the pen wedges partway down and hovers. A countersink only relieves the top 1 mm, so it never reaches the part of the bore doing the wedging — exactly what the second report says.

Both obvious levers were blocked. A wider bore or a deeper funnel would each buy a little clearance, and both spend it out of the hole spacing on the ellipse and trefoil that step four had already paid for once.

round one 3 mm bore through a 4 mm plate with a 1 mm funnel
3.0 mm bore, 4 mm of plate to get through.
round two 3 mm bore through a 2.5 mm plate with a 0.6 mm funnel
Same bore, 2.5 mm of plate. The pen has 1.5 mm less of itself to force through.

the plate

Thinning is the one lever that costs nothing already spent. Hole spacing is a radial constraint with no relationship to thickness, so the ellipse and trefoil keep every hole step five left them.

-wheel_thickness = 4;
+wheel_thickness = 2.5;
-pen_cs_depth    = 1.0;   // how deep the funnel cuts
+pen_cs_depth    = 0.6;   // how deep the funnel cuts. Scaled with the plate
plate4.0 → 2.5 mm
funnel depth1.0 → 0.6 mm
straight bore left to guide the pen1.9 mm
holes lost to this changenone
ring, and its 7 mm toothed boreuntouched
whole set, print time13.0 → 10.7 h
whole set, filament62.8 → 53.8 m

2.5 mm is near a shop-bought wheel. The teeth are 3.375 mm tall, so tooth engagement is nowhere near the limit, and the ring's internal teeth already run the full 7 mm of ring-plus-lip height, so nothing about the ring had to move.

This is the number that is still a guess. Take a caliper to your pen 2 mm back from the nib; if that is under 3 mm the plate is thin enough. If not, drop wheel_thickness again — 2.0 prints perfectly well. One 24T wheel settles it in about twenty minutes rather than ten hours.

the layout

I also note that the layout of the holes is currently not likely to create spirals or other compelling shapes. Richard, same report

Half right, and the half that is right can be pointed at exactly. Rather than agree, the figure every hole traces was computed and drawn.

What a hole draws depends on how far out it sits as a fraction of the pitch radius, written d/rp below. Near the middle it traces something close to a circle whatever the wheel; out near the rim it traces the sharp cusped star a spirograph is bought for. Angular position only rotates the result, so the golden-angle scatter costs nothing.

Across the set the variety is real — lobe counts of 3, 4, 6, 8, 12, 16, 24 and 32, and dense rosettes on the 52 and 63. But pen_r0 was an absolute 5.5 mm, and an absolute radius means something different on every wheel: 31% of the pitch radius on the 24, and a useless 9% on the 80. The innermost holes of the big wheels drew cramped knots worth none of the plate.

Six spirograph figures. The top row, in red, shows three cramped tangled shapes traced from the old inner hole positions. The bottom row, in green, shows three clean six-petal rosettes traced from the new positions.
The 80T wheel's first, third and sixth holes. Red = where they were, green = where they are now. Computed hypotrochoids for the real 96-tooth ring, not illustrations.
// The figure a hole draws is set by how far out it sits as a fraction of the
// pitch radius, not by its distance in millimetres.
function pen_r_min(n) = max(pen_r0, pen_r0_frac * gear_module * n / 2);
80T range, d/rp0.09–0.89 → 0.25–0.89
80T and 72T hole count24, unchanged
24T — the label still binds0.31–0.65, unchanged
holes across the set176 → 162

The fourteen holes dropped are all near-circles. The two biggest wheels lose nothing and gain a usable range.

the check

Two funnels running into one another is a fault no render, no slicer and no bed check would report. The geometry stays a clean manifold, it fits the plate, it slices. It just draws badly. So the model proves the spacing on every render.

for (t = wheel_teeth)
    assert(min_pitch(wheel_hole_pts(t)) >= pen_pitch_min(),
           str(t, "T: pen holes are closer than their countersinks are wide"));
for (s = nc_shapes)
    assert(min_pitch(nc_hole_pts(s)) >= pen_pitch_min(),
           str(s[0], ": pen holes still crowd after thinning"));

An assertion that has never failed is not evidence of anything, so it was made to fail on purpose — squeeze the spiral, and the smallest wheel is the first to go:

$ openscad -D "pen_spiral_dr=0.4" models/spirograph.scad
ERROR: Assertion '(min_pitch(wheel_hole_pts(t)) >= pen_pitch_min())' failed:
       "24T: pen holes are closer than their countersinks are wide"

This is the step the walkthrough on the main page calls verify, and the reason it exists: for a part that has to work, the checks that matter are the ones you write yourself. Neither round of this job would have been caught by anything downstream of CAD.

the proof

Everything below ran after both rounds, on this machine.

before 36 tooth wheel, 4 mm thick, with narrow straight-walled pen holes
36T — 4 mm plate, 2.4 mm holes, square rims, 11 holes.
after 36 tooth wheel, 2.5 mm thick, with wider countersunk pen holes
36T — 2.5 mm plate, 3.0 mm countersunk holes, 10 holes. Same camera.
$ python -m cadloop.gearcheck
24T         24     0.000000  pass
                  ...
80T         80     0.000000  pass
ellipse     27     0.000000  pass
egg         20     0.000000  pass
trefoil     23     0.000000  pass

14/14 parts mesh cleanly
no parts overlap on the sheet
full sheet rendersmanifold, NoError
parts meshing14 / 14
spacing assertionspass, and proven to fail
test suite170 passed
plates, all proven on the bed5 / 5
print time, whole set10.7 h

Sliced for a Creality Ender-3 V3 SE, 0.4 nozzle, PLA. Every extruding move in all five G-code files was read back and confirmed inside the printable area. plate_2 sits 2.2 mm from the bed edge and wants a brim.

Not checked, and not checkable from here: whether 2.5 mm and 3.0 mm suit your pen. That needs one wheel printed and a caliper. Both are single numbers, and the hole count, rim clearance, thinning and pattern range all follow them.