Flushed with success on the small-hole front, I conjured up a large hole testpiece using the same HoleAdjust function that proved unnecessary with the little ones:

The first version didn’t have the cross bars, which turned out to be a mistake, because the individual rings distorted even under minimal pressure from the calipers:

However, measuring as delicately as I could, the holes seemed a scant 0.20 mm too small, more or less, kinda-sorta:
Nominal | Nom+0.0 |
10 | 9.83 |
20 | 19.75 |
30 | 29.85 |
40 | 39.84 |
50 | 49.84 |
60 | 59.72 |
70 | 64.76 |
80 | 79.28 |
90 | 89.77 |
So I fed in HoleFinagle = 0.20 and the second iteration looks like it’d make a great, albeit leaky, coaster:

Measuring those holes across the center with the calipers on facets (rather than vertices), produced somewhat more stable results:
Nominal | Nom+0.20 |
10 | 10.08 |
20 | 20.17 |
30 | 30.08 |
40 | 40.08 |
50 | 50.00 |
60 | 60.02 |
70 | 70.05 |
80 | 79.98 |
90 | 90.07 |
Frankly, I don’t believe those two least-significant digits, either, because a different set of measurements across different facets looked like this:
Nominal | Nom+0.20 |
10 | 10.13 |
20 | 20.11 |
30 | 29.84 |
40 | 39.90 |
50 | 49.88 |
60 | 59.90 |
70 | 69.84 |
80 | 79.82 |
90 | 89.66 |
I also printed a testpiece with HoleFinagle = 0.25 that averaged, by in-the-head computation, about 0.05 larger than that, so the hole diameter compensation does exactly what it should.
Applying the calipers to the 10.0 mm hole in the small-hole testpiece gives about the same result as in this one. The fact that HoleFinagle is different poses a bit of a mystery…
The only thing I can conclude is that the measurement variation and the printing variation match up pretty closely: the actual diameter depends more on where it’s measured than anything else. The holes are pretty nearly the intended size and, should the exact size matter, you (well, I) must print at least one to throw away.
All in all, a tenth of a millimeter is Good Enough. Selah.
Oh. The ODs are marginally too small, even using PolyCyl.
The OpenSCAD source, with both adjustments set to neutral:
// Large circle diameter calibration // Ed Nisley KE4ZNU - Nov 2011 //------- //- Extrusion parameters must match reality! // Print with +1 shells, 3 solid layers, 0.2 infill ThreadThick = 0.33; ThreadWidth = 2.0 * ThreadThick; HoleFinagle = 0.00; HoleFudge = 1.00; function HoleAdjust(Diameter) = HoleFudge*Diameter + HoleFinagle; Protrusion = 0.1; // make holes end cleanly function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); //------- // Dimensions Width = 2.5; Thickness = IntegerMultiple(2.0,ThreadThick); DiaStep = 10.0; NumCircles = 9; echo(str("Width: ",Width)); echo(str("Thickness: ",Thickness)); BarLength = (NumCircles + 1)*DiaStep; //------- module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); FixDia = Dia / cos(180/Sides); cylinder(r=HoleAdjust(FixDia)/2,h=Height,$fn=Sides); } module ShowPegGrid(Space = 10.0,Size = 1.0) { Range = floor(50 / Space); for (x=[-Range:Range]) for (y=[-Range:Range]) translate([x*Space,y*Space,Size/2]) %cube(Size,center=true); } //------ module Ring(RingID,Width,Thick) { difference() { PolyCyl((RingID + 2*Width),Thick); translate([0,0,-Protrusion]) PolyCyl(RingID,(Thick + 2*Protrusion)); } } //------ ShowPegGrid(); union () { for (Index = [1:NumCircles]) Ring(Index*DiaStep,Width,Thickness); for (Index = [-1,1]) rotate(Index*45) translate([-BarLength/2,-Width/2,0]) cube([BarLength,Width,Thickness]); }