# Posts Tagged M2

### Generic PCB Holder: Boost Power Supply

Posted by Ed in Electronics Workbench, Machine Shop, Software on 2015-01-29

The DC-DC boost power supply for the LED needle lights has four mounting holes, two completely blocked by the heatsink and the others against components with no clearance for screw heads, *soooo* …

3D printing to the rescue:

Now that the hulking ET227 operates in saturation mode, I removed the blower to make room for the power supply. Two strips of double-stick foam tape fasten the holder to the removable tray inside the Dell GX270’s case.

It’s basically a rounded slab with recesses for the PCB and clearance for solder-side components:

The solid model shows the screw holes sitting just about tangent to the PCB recess:

That’s using the new OpenSCAD with length scales along each axis; they won’t quite replace my layout grid over the XY plane, but they certainly don’t require as much computation.

I knew my lifetime supply of self-tapping hex head 4-40 screws would come in handy for something:

The program needs to know the PCB dimensions and how much clearance you want for the stuff hanging off the bottom:

PCBoard = [66,35,IntegerMultiple(1.8,ThreadThick)]; BottomParts = [[1.5,-1.0,0,0], // xyz offset of part envelope [60.0,37.0,IntegerMultiple(3.0,ThreadThick)]]; // xyz envelope size (z should be generous)

That’s good enough for my simple needs.

The hole locations form a list-of-vectors that the code iterates through:

Holes = [ // PCB mounting screw holes: XY + rotation [Margin - ScrewOffset,MountBase[Y]/2,180/6], [MountBase[X] - Margin + ScrewOffset/sqrt(2),MountBase[Y] - Margin + ScrewOffset/sqrt(2),15], [MountBase[X] - Margin + ScrewOffset/sqrt(2),Margin - ScrewOffset/sqrt(2),-15], ]; ... snippage ... for (h = Holes) { translate([h[X],h[Y],-Protrusion]) rotate(h[Z]) PolyCyl(Tap4_40,MountBase[Z] + 2*Protrusion,6); }

That’s the first occasion I’ve had to try iterating a list and It Just Worked; I must break the index habit. The newest OpenSCAD version has Python-ish list comprehensions which ought to come in handy for something.

The “Z coordinate” of each hole position gives its rotation, so I could snuggle them up a bit closer to the edge by forcing the proper polygon orientation. The square roots in the second two holes make them tangent to the corners of the PCB, rather than the sides, which wasn’t true for the first picture. Fortunately, the washer head of those screws turned out to be just big enough to capture the PCB anyway.

The OpenSCAD source code:

// PCB mounting bracket for XW029 DC-DC booster // Ed Nisley - KE4ZNU - January 2015 Layout = "Build"; // PCB Block Mount Build //- Extrusion parameters must match reality! // Print with 4 shells and 3 solid layers ThreadThick = 0.20; ThreadWidth = 0.40; HoleWindage = 0.2; // extra clearance Protrusion = 0.1; // make holes end cleanly AlignPinOD = 1.70; // assembly alignment pins: filament dia function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); X = 0; // useful subscripts Y = 1; Z = 2; //---------------------- // Dimensions inch = 25.4; Tap4_40 = 0.089 * inch; Clear4_40 = 0.110 * inch; Head4_40 = 0.211 * inch; Head4_40Thick = 0.065 * inch; Nut4_40Dia = 0.228 * inch; Nut4_40Thick = 0.086 * inch; Washer4_40OD = 0.270 * inch; Washer4_40ID = 0.123 * inch; PCBoard = [66,35,IntegerMultiple(1.8,ThreadThick)]; BottomParts = [[1.5,-1.0,0,0], // xyz offset of part envelope [60.0,37.0,IntegerMultiple(3.0,ThreadThick)]]; // xyz envelope size (z should be generous) Margin = IntegerMultiple(Washer4_40OD,ThreadWidth); MountBase = [PCBoard[X] + 2*Margin, PCBoard[Y] + 2*Margin, IntegerMultiple(5.0,ThreadThick) + PCBoard[Z] + BottomParts[1][Z] ]; echo("Mount base: ",MountBase); ScrewOffset = Clear4_40/2; Holes = [ // PCB mounting screw holes: XY + rotation [Margin - ScrewOffset,MountBase[Y]/2,180/6], [MountBase[X] - Margin + ScrewOffset/sqrt(2),MountBase[Y] - Margin + ScrewOffset/sqrt(2),15], [MountBase[X] - Margin + ScrewOffset/sqrt(2),Margin - ScrewOffset/sqrt(2),-15], ]; CornerRadius = Washer4_40OD / 2; //---------------------- // Useful routines 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=(FixDia + HoleWindage)/2, h=Height, $fn=Sides); } module ShowPegGrid(Space = 10.0,Size = 1.0) { RangeX = floor(100 / Space); RangeY = floor(125 / Space); for (x=[-RangeX:RangeX]) for (y=[-RangeY:RangeY]) translate([x*Space,y*Space,Size/2]) %cube(Size,center=true); } //---------------------- // Build things module PCB() { union() { cube(PCBoard); translate(BottomParts[X] - [0,0,BottomParts[1][Z]]) cube(BottomParts[Y] + [0,0,Protrusion]); } } module Block() { translate([MountBase[X]/2,MountBase[Y]/2,0]) hull() for (i = [-1,1], j = [-1,1]) translate([i*(MountBase[X]/2 - CornerRadius),j*(MountBase[Y]/2 - CornerRadius)],0) cylinder(r=CornerRadius,h=MountBase[Z] - Protrusion,$fn=8*4); } module Mount() { difference() { Block(); translate([MountBase[X]/2 - PCBoard[X]/2 + BottomParts[0][X] - Protrusion, -MountBase[Y]/2, MountBase[Z] - PCBoard[Z] - BottomParts[1][Z]]) cube([BottomParts[1][X] + 2*Protrusion, 2*MountBase[Y], 2*BottomParts[1][Z]]); translate([MountBase[X]/2 - PCBoard[X]/2, // PCB recess MountBase[Y]/2 - PCBoard[Y]/2, MountBase[Z] - PCBoard[Z]]) PCB(); for (h = Holes) { translate([h[X],h[Y],-Protrusion]) rotate(h[Z]) PolyCyl(Tap4_40,MountBase[Z] + 2*Protrusion,6); } } } //ShowPegGrid(); if (Layout == "PCB") PCB(); if (Layout == "Block") Block(); if (Layout == "Mount") Mount(); if (Layout == "Build") translate([-MountBase[X]/2,-MountBase[Y]/2,0]) Mount();

### Monthly Image: Spherometer Measurements

Posted by Ed in Machine Shop, Photography & Images, Science on 2015-01-15

Our Larval Engineer volunteered to convert the lens from a defunct magnifying desk lamp into a hand-held magnifier; there’s more to that story than is relevant here. I bulldozed her into making a solid model of the lens before starting on the hand-holdable design, thus providing a Thing to contemplate while working out the holder details.

That justified excavating a spherometer from the heap to determine the radius of curvature for the lens:

You must know either the average radius / diameter of the pins or the average pin-to-pin distance. We used a quick-and-dirty measurement for the radius, but after things settled down, I used a slightly more rigorous approach. Spotting the pins on carbon paper (!) produced these numbers:

The vertical scale has hard-metric divisions: 1 mm on the post and 0.01 on the dial. You’d therefore expect the pins to be a hard metric distance apart, but the 25.28 mm average radius suggests a crappy hard-inch layout. It was, of course, a long-ago surplus find without provenance.

The 43.91 mm average pin-to-pin distance works out to a 50.7 mm bolt circle diameter = 25.35 mm radius, which is kinda-sorta close to the 25.28 mm average radius. I suppose averaging the averages would slightly improve things, but …

The vertical distance for the lens in question was 0.90 mm, at least for our purposes. That’s the sagitta, which sounds cool enough to justify this whole exercise right there. It’s 100 mm in diameter and the ground edge is 2.8 mm thick, although the latter is subject to some debate.

Using the BCD, the chord equation applies:

- Height m = 0.90 mm
- Base c = 50.7 mm
- Lens radius r = (m
^{2}+ c^{2}/4) / 2m = 357.46 mm

Using the pin-to-pin distance, the spherometer equation applies:

- Pin-to-pin a = 43.91 mm
- Sagitta h = 0.90 mm
- Lens radius R = (h/2) + (a
^{2}/ 6h) = 357.50 mm

Close enough, methinks.

Solving the chord equation for the total height of each convex side above the edge:

- Base c = 100 mm
- Lens radius r = 357.5 mm
- Height m = r – sqrt(r
^{2}-c^{2}/4) = 3.5 mm

So the whole lens should be 2 · 3.5 + 2.8 = 9.8 mm thick. It’s actually 10.15 mm, which says they were probably trying for 10.0 mm and I’m measuring the edge thickness wrong.

She submitted to all this nonsense with good grace and cooked up an OpenSCAD model that prints the “lens” in two halves:

Alas, those thin flanges have too little area on the platform to resist the contraction of the plastic above, so they didn’t fit together very well at all:

We figured a large brim would solve that problem, but then it was time for her to return to the hot, fast core of college life…

### 3D Printed Handcuffs

Posted by Ed in Machine Shop, Oddities on 2015-01-13

A friend who read about my chain mail armor asked about handcuffs, so I ran off one of gianteye’s Printable Handcuffs V1.0:

Alas, that shows the difficulty of using an STL file designed for a different printer, as the interlocking parts didn’t even come close to fitting and required major abrasive adjustment with a Dremel. One of the few successful prints reported on Thingiverse seems involve a commercial printer, so it’s not just the M2’s problem.

I’m not sufficiently motivated to conjure an OpenSCAD model right now…

### 3D Printed Chain Mail Armor – Zombie Hunter Edition

Posted by Ed in Home Ec, Machine Shop on 2015-01-12

Reducing the link bars to 4×4 threads produced a diminutive patch:

Most of the dark smudges come from optical effects in the natural PLA filament, but the second-from-upper-left armor button contains a dollop of black PLA left in the nozzle from the end of that spool; running meters and meters of filament through the extruder isn’t enough to clean the interior. I now have some filament intended to clean the extruder, but it arrived after the black ran out.

Comparing the patch with the original buttons shows the size difference:

A trial fit suggested a 5×5 patch would fit better, so …

The whip stitching accentuates the jacket’s style. ~~We~~ I think a glittery piping cord square around the armor links would spiff it up enormously *and* hide the open links, but that’s in the nature of fine tuning.

I’ll eventually see what happens with 3×3 thread = 1.2×0.6 mm links, which may be too small for reliable bridging and too delicate for anything other the finest evening wear.

### Rounded Cable Clips

Posted by Ed in Electronics Workbench, Machine Shop, Software on 2015-01-08

This isn’t quite the smoothly rounded clip I had in mind:

It seems somewhat better looking than the square design, though:

I ran off a few of both styles to have some on hand:

They’re in a bag until I install the new LED strips and needle light.

The OpenSCAD source code:

// LED Cable Clips // Ed Nisley - KE4ZNU - October 2014 Layout = "Oval"; // Oval Square Build //- Extrusion parameters must match reality! ThreadThick = 0.20; ThreadWidth = 0.40; HoleWindage = 0.2; // extra clearance Protrusion = 0.1; // make holes end cleanly AlignPinOD = 1.70; // assembly alignment pins: filament dia function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); //---------------------- // Dimensions Base = [12.0,12.0,IntegerMultiple(2.0,ThreadThick)]; // base over sticky square CableOD = 2.0; BendRadius = 3.0; Bollard = [BendRadius,(sqrt(2)*Base[0]/2 - CableOD - BendRadius),2*CableOD]; B_BOT = 0; B_TOP = 1; B_LEN = 2; NumSides = (Shape == "Square") ? 5*4 : 6*3; //---------------------- // Useful routines 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=(FixDia + HoleWindage)/2, h=Height, $fn=Sides); } module ShowPegGrid(Space = 10.0,Size = 1.0) { RangeX = floor(100 / Space); RangeY = floor(125 / Space); for (x=[-RangeX:RangeX]) for (y=[-RangeY:RangeY]) translate([x*Space,y*Space,Size/2]) %cube(Size,center=true); } //-- Square clip with central bollard module SquareBollard() { intersection() { translate([0,0,(Base[2] + Bollard[B_LEN])/2]) // overall XYZ outline cube(Base + [0,0,Bollard[2]],center=true); union() { translate([0,0,Base[2]/2]) // oversize mount base scale([2,2,1]) cube(Base,center=true); for (i=[-1,1] , j=[-1,1]) { // corner bollards translate([i*Base[0]/2,j*Base[1]/2,(Base[2] - Protrusion)]) rotate(180/NumSides) cylinder(r=Bollard[B_BOT],h=(Bollard[B_LEN] + Protrusion),center=false,$fn=NumSides); translate([0,0,(Base[2] - Protrusion)]) // center tapered bollard cylinder(r1=Bollard[B_BOT],r2=Bollard[B_TOP], h=(Bollard[B_LEN] + Protrusion), center=false,$fn=NumSides); } } } } //-- Oval clip with central passage module OvalPass() { intersection() { translate([0,0,(Base[2] + Bollard[B_LEN])/2]) // overall XYZ outline cube(Base + [0,0,2*CableOD],center=true); union() { translate([0,0,Base[2]/2]) // oversize mount base scale([2,2,1]) cube(Base,center=true); for (j=[-1,1]) // bending ovals translate([0,j*Base[1]/2,(Base[2] - Protrusion)]) resize([Base[0]/0.75,0,0]) cylinder(d1=0.75*(Base[1]-CableOD),d2=(Base[1]-CableOD)/cos(180/NumSides), h=(Bollard[B_LEN] + Protrusion), center=false,$fn=NumSides); } } /* # translate([0,0,6]) rotate([0,90,0]) cylinder(d=CableOD,h=10,center=true,$fn=48); */ } //---------------------- // Build it ShowPegGrid(); if (Layout == "Square") SquareBollard(); if (Layout == "Oval") OvalPass();

### OpenSCAD: Quantized Vertices

Posted by Ed in Machine Shop, Software on 2015-01-02

Back when I started fiddling with 3D printed chain mail, the whole process from model to plastic worked wonderfully well. That continued with the larger sheets, but now, occasionally, the OpenSCAD model would produce weirdly sliced links. Depending on nothing repeatable, some links wouldn’t bridge correctly: the thread paths in the bottom layer across the gap would mysteriously stop just short of one pillar, return to the start, and leave an unsupported shelf that would, of course, fall into the gap.

Shortly before Christmas, I managed to get a consistent failure that manifested differently: upon loading the STL file, Slic3r would quietly perform dozens of automatic corrections that (sometimes!) produced bizarrely distorted results. Feeding a failing model into Meshlab showed an irregular assortment of “self intersecting faces”, highlighted in red:

Although all four outer links in that image come from the same OpenSCAD module with identical sizes, they don’t all exhibit the same problem in the (nominally identical) faces on each of their four corners. In fact, those faces come from the intersection of two square slabs, carefully sized and positioned to avoid creating coincident planes:

The central opening comes from a similar, slightly smaller, intersected-squares shape, but all four interior corner faces in each link show that they’re self-intersecting.

The STL looked fine in Meshlab, except for the highlit self-intersecting faces, so the geometry seemed OK.

When Slic3r autocorrected the “problems”, it apparently removed one vertex on the bottom surface of each bar, deleted the triangles connected to that vertex, then repaired the mesh to produce a delightfully symmetric pattern:

Although the links are resolutely symmetric, Slic3r seemed happy with the identical vertices at the other end of the bar.

Unfortunately, the resulting G-Code won’t produce good links:

So, shortly before Christmas, I filed an issue on OpenSCAD’s Github repository.

The ensuing discussion showed that Meshlab flags faces as “self intersecting” when they have *different* vertices, even if their values are numerically equal, as well as vertices that differ by teeny amounts. Slic3r applies slightly different criteria to vertices & faces when it automagically corrects “problems” in the STL file, so that Meshlab may:

- Highlight faces that don’t bother Slic3r
- Apply the same highlight to faces that cause horrible problems

I don’t profess to understand much of that and may have the details wrong, but, apparently, OpenSCAD formerly used quantized coordinates that ensured all vertices within a tiny volume would have the same numeric value. In particular, all three faces that meet at a common point would, in fact, have numerically equal coordinate values for that point. The STL file format consists of a list of separate triangles, each with three coordinates for each of the three axes, and (without quantization) it was entirely possible for each of the three triangles with a common point to have three very slightly different positions for that point.

In theoretic terms, quantized coordinates cause horrible problems during geometric manipulation, because numeric values that aren’t exact can make repeated transformations come out wrong; running an object through a transformation and it’s inverse might not yield an object *identical* to the original one.

In practical terms, it seems that slicers and STL repair algorithms can reach incorrect conclusions based on minute differences produced by floating-point operations and numeric-to-text conversions. Those differences depend on slight changes in position, rotation, and size, so doing *anything* to the model produces completely different results.

That notwithstanding, the day after Christmas brought a new OpenSCAD version that uses quantized coordinates. A bit of rummaging in the source shows that the 3D grid (defined in `src/grid.h`

) isn’t all that coarse:

const double GRID_FINE = 0.00000095367431640625;

STL files don’t carry units, so that could be in either millimeters (the Slic3r / RepRap convention) or inches (Sketchup, but we won’t go there). It’s exactly 1/1024^{2}, in case you were wondering, which produces a 5% speedup in the geometry engine compared to the more human-readable 1/1000^{2}.

With that commit in hand, all the chain mail links slice perfectly again.

A very nice Christmas present, indeed!

Thanks, Marius…

### MakerGear M2: Better Lighting, Redux

Posted by Ed in Electronics Workbench, Machine Shop, Photography & Images on 2014-12-12

A surplus haul of 24 V / 150 mA white LED panels arrived:

I wired a pair to a 24 V wall wart and stuck them under the M2’s bridge supporting the X stage:

I thought about epoxying them in place to get better heatsinking to the metal bridge. The ever-trustworthy description said the big copper baseplate meant the panels didn’t need any heatsinking, so I used tapeless sticky and will hope for the best. Should the sticky give out, *then* I’ll use epoxy.

They’re much better than the previous white LED strip, although it’s tough to tell in the pictures. The chain mail armor appears under the new lights; some older pictures will creep in from time to time.

## Blowback