Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Category: Software
General-purpose computers doing something specific
One of Mary’s gardening buddies gave her a Taylor rain gauge he picked up at a closeout sale, but the exceedingly thin aluminum holder obviously wasn’t up to the task:
Taylor Rain Gauge – OEM metal stake
I briefly considered 3D printing a better bracket, but came to my senses:
Taylor Rain Gauge holder – front
A generous fillet of tan JB PlasticBonder holds the thin aluminum clamp ring to the top of the dagger spike:
Taylor Rain Gauge holder – rear
The spike is 6.3 mm acrylic and should survive for a while despite the stress-raiser corners. The next iteration will have radiused corners and could last longer:
Taylor Rain Gauge Holder – LightBurn layout
The holes will fit 4 mm screws, although the OEM holder isn’t good for more than 3 mm.
Having just replaced the shower faucet cartridge, the knob insert (probably from 1998, according to a label on the shower stall) could also use some improvement:
Delta 1400 Shower Faucet knob insert – front
That oblong blue tint is water. The shattered sections formerly had small fingers holding the insert into the knob:
Delta 1400 Shower Faucet knob insert – rear
Pry the aluminum disk out of the insert and scan it:
Delta Shower Faucet – label scan
There is no feature in the knob to capture the semicircular notch at the arrow tip, so the disk can rotate as it pleases. I think the arrow should point to the OFF label on the bezel when the water is turned off, but who knows?
Import it into Inkscape, whereupon it becomes obvious the printed legend is not centered on the disk, lay suitable construction lines & circles, then draw similar shapes:
Delta Shower Faucet – Inkscape layout
I located the circles at the Inkscape page corner to put their center at the (0,0) origin with the arrow pointed along the X axis to simplify importing it into OpenSCAD.
The three useful graphic features go on separate layers so OpenSCAD can treat them as separate objects:
The KnobAngle rotation comes from the angle of the features inside the knob that locate the insert, which are aligned horizontally here, but at about 30° when the knob is installed on the faucet :
Delta 1400 Shower Faucet knob – insert recess features
The knob shined up surprisingly well for being three decades old; that photo is as-found.
Import the Inkscape graphics into OpenSCAD and align them an itsy above the top of the insert structure to prevent Z fighting without triggering the slicer into adding another layer:
Those three shapes must be handled separately, lest OpenSCAD combine them into one thing that PrusaSlicer won’t recognize as distinct shapes. There’s no need to subtract them from the main insert shape, but getting separate colors to come out right is definitely not straightforward.
Which looks like this, with cheerful colors that need not correspond to the printer filaments:
Delta Shower Faucet Insert – solid model
Normally I have a set of Build transformations to orient the thing for printing, but doing a simple rotation to put the top down on the platform also blows away the separate nature of the graphics.
I use the EIA color code sequence in PrusaSlicer so I can identify the filament number by eye:
Shower Fauce Knob Insert – PrusaSlicer preview
A little while later:
Delta 1400 Shower Faucet knob insert – installed
The insert is a loose fit in the knob, held in place by good double-sided foam tape to the screw securing the knob. I decided to not bother with little fingers, because I loves me some simple removable adhesive action.
Yeah, you can buy an entire replacement knob for ten bucks, but where’s the fun in that?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Run the program ten times to generate ten SVG images:
for i in {00..09} ; do python Layers\ -\ 24x18.py --layernum=$i --colors=9 > Test_$i.svg ; done
The LightBurn layout dwarfs the machine platform:
Layered Paper – circular colors – 24x18in – LightBurn layout
Fire The Laser ten times and you get a wall hanging:
Layered Paper – 24×18 – trial alignment
That’s a trial alignment atop a cardboard box on the Basement Shop floor, because gluing those 24×18 inch sheets of paper requires time on the Sewing Table, which is currently occupied by a much higher priority project. The brown innermost circle in the design is entirely separate from the brown Amazon cardboard box underneath everything.
Fairly obviously, you’d want something other than brown at the focal point of that design, but following the EIA color code gives me some confidence the result matches the intention. Feel free to tart it up with your own colors.
I laid a 29×23 inch sheet of sketch paper on the honeycomb, distributed neodymium bar magnets around the perimeter, and cut a 24×18 rectangle out of the middle:
Layered Paper – 24×18 – brown squares
Those squares are the cutouts from the brown sheet, minus what you see in the lead picture.
The black rectangle on the left of the LightBurn layout above is the 24×18 inch cut for the fixture. Centering that rectangle on the LightBurn layout (click-select, Ctrl-D to duplicate, then hit P to move it to the center) means aligning each of the ten patterns requires nothing more than the same click-select / dupe / P, with no delicate fiddling.
Then just lay each colored sheet into the hole and it’s properly aligned. Because the machine homes to the same physical location every time it’s turned on and the fixture is mmm fixed to the platform, cutting all ten sheets over the course of two days proceeded smoothly.
Cutting 2537 holes in the black mask takes a little under an hour:
Layered Paper – 24×18 – cutting black
The other sheets have fewer holes and go progressively faster:
Layered Paper – 24×18 – cutting yellow
The white sheet on the bottom has four alignment holes and four layer ID holes, so the cuts take a few seconds.
Thresholding the distance from a randomly chosen point creates circular rainbows:
CenterPoint = (choice(range(args.width)),choice(range(args.height)))
CellMatrix = [[math.hypot(x - CenterPoint[X],y - CenterPoint[Y])
for y in range(args.height)]
for x in range(args.width)]
dmax = max(list(chain.from_iterable(CellMatrix)))
LayerThreshold = (ThisLayer/Layers)*dmax
The Python program generates one SVG image file representing a single layer, as determined by the Bash one-liner invoking it:
for i in {00..16} ; do python Layers\ -\ 200mm.py > Test_$i.svg ; done
In real life you’d also use a different random seed for each set of layers, but that’s just another command line optIon.
Import those 17 SVG images into LightBurn, arrange neatly, snap each one to the middle of the workspace grid (and thus the aligned template), then Fire The Laser:
Feeding paper into the laser in rainbow (actually, heavily augmented / infilled EIA color code) order, plus the black mask, produces the aforementioned pleasing result:
Layered Paper – rainbow oblique view
Glue the sheets in the assembly fixture:
Layered Paper – gluing fixture side view
The white layer is uncut, other than the four alignment holes (with a rivnut poking up) and its binary layer number (16, backwards because upside-down), and appears in only the farthest corners of the rainbow.
Protip: doing the stack upside-down means you smear glue stick on the hidden side of each sheet. If you avoid slobbering glue into the cut square holes, nothing can go wrong.
Making these things produces the happiest chip tray ever:
Layered Paper – rainbow chip tray
I swept half a dozen pictures worth of squares into a small box and gave it away to someone with a larger small-child cross-section than mine, whereupon a slight finger fumble turned the contents into a glitter bomb. Sorry ’bout that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# cut layer ID holes except on mask layer
if ThisLayer > 0:
c = ((1,1))
h = f'{ThisLayer:0{Layers.bit_length()}b}'
for i in range(Layers.bit_length()):
SheetEls.append(
svg.Circle(
cx=as_mm(SheetCenter[X] + c[X]*AlignOC[X]/2 - (i + 2)*AlignOD),
cy=as_mm(SheetCenter[Y] + c[Y]*AlignOC[Y]/2),
r=AlignOD/4 if h[-(i + 1)] == '1' else AlignOD/8,
stroke=SheetCut,
stroke_width=DefStroke,
fill="none",
)
)
Filling the matrix of blocks with random numbers turned out to be a one-liner:
CellMatrix = [[randint(1,args.colors) for _ in range(args.height)] for _ in range(args.width)]
That matrix is a constant for all the layers, which is why you must feed the program the same random number seed to generate the layers.
Given the layer number and that matrix, deciding what to do for each hole is a walk through the cells:
MatrixEls = [] # accumulates matrix cuts
for i in range(args.width):
x =i*CellOC[X]
for j in range(args.height):
y = j*CellOC[Y]
if ThisLayer == 0: # black mask
s = HeavyCellCut
elif ThisLayer < CellMatrix[i][j]: # rest of sheets above color layer
s = CellCut
else:
s = Tooling # at or below color layer
MatrixEls.append(
svg.Rect(
x=as_mm(SheetCenter[X] - MatrixOA[X]/2 + x),
y=as_mm(SheetCenter[Y] - MatrixOA[Y]/2 + y),
width=as_mm(CellSize[X]),
height=as_mm(CellSize[Y]),
stroke=s,
stroke_width=DefStroke,
fill="none",
)
)
After accumulating all the other elements in similar lists, this creates and emits the entire SVG file to stdout:
The whole program has a bit more going on, but those are the high points.
Invoke the program with a Bash one-liner:
for i in {00..08} ; do python Layers.py --layernum=$i > Test_$i.svg ; done
That produces nine SVG image files that you import into LightBurn and arrange in a tidy array:
Layered Paper – Random Blocks – MVP – LightBurn import
I discovered that holding down the Shift key while importing the SVG files stacks them at the workspace origin (the upper-right corner for my machine) in the order of the file names, so clicking on the stack selects successive layers in the right order; just drop each one wherever you need it, then tidy the lineup.
The Python program sets the vector stroke colors using LightBurn palette values, so that LightBurn automagically assigns them to the appropriate layers. It turns out the black paper I used for the mask requires different speed / power values than the other colored paper.
I put the alignment features on a different layer than the matrix holes to make them more visible, even though they have the same speed / power values.
Align the template so the middle of the layer pattern is in the middle of the grid, then use LightBurn’s Print and Cut to align the template with the fixture on the laser platform:
Layered Paper – Random Blocks – MVP – template
Then the process requires just a few clicks per layer:
Drop a sheet of paper into the fixture
Click to select a layer layout
Ctrl-D to duplicate it
P to snap it to the middle of the grid
Alt-S to Fire The Laser
Del to delete that layer (which is why it’s a duplicate!)
Iterate until done!
Which looks pretty much like you’d expect:
Layered Paper – Random Blocks – cutting
Take the stack of paper to the workbench, use an Xacto knife to cut the tabs holding the square into the Letter page, apply glue stick, stack in the fixture, and iterate to create a solid sheet with lots of holes:
Layered Paper – Random Blocks – MVP
More refinement is in order, but that’s the overview …
Got it done the day after the old hose split, glued it on the hose with E6000+, installed it the next morning, whereupon the weather delivered three inches of rain. It’ll get screwed onto the faucet in a few days …
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The next step involves creating a corresponding set of LightBurn layouts to burn those holes out of colored paper sheets to produce layered paper art:
Random Blocks – framed
I know it’s art, because that’s what I was thinking when I made it.
Setting up the LightBurn layouts requires enough manual effort to make the whole thing impractical except as a testcase to see how it all worked out. An overview of the LightBurn workspace:
Random Blocks – 16×16 – LightBurn layout overview
The little bitty grid in the upper left quadrant represents the 700×500 platform of my laser and each of the blue squares is 159 mm on a side. I tend to not delete the intermediate steps, because they serve as some sort of documentation the next time I wonder how I did that thing.
So, we begin.
Import the Inkscape SVG file:
Random Blocks – 16×16 – LightBurn SVG import
The blue outer square and the blue text identifying it are on LightBurn’s T2 tool layer, with the black squares on the C00 layer. All of that happens automagically, because I used colors from the LightBurn palette in Inkscape.
The lonely square in the upper right is the template from which the other 256 squares were cloned, but it has no further purpose in life.
The 16×16 grid consists of sixteen overlaid groups, which need sorting out for ease of access, so drag each one off into a more useful arrangement:
Random Blocks – 16×16 – LightBurn sheet separation
Note that each of the 256 possible positions has a square in only one of those groups.
Each of the 16 groups corresponds to a sheet of paper, with the squares indicating holes exposing the sheet below it. The color of each square, as seen from the top of the stack, comes from the first sheet in the stack without a hole. Perforce, every sheet above the one without a hole must have a hole, which means you must merge all those sheets.
Line up (duplicates of) those 16 groups in the vertical line forming the left column in this arrangement:
Random Blocks – 16×16 – LightBurn array duplication
The top group is the layer I named H000 in Inkscape, with the others in order down to H337 on the bottom. You can see why labeling them is pretty much required.
I should have equalized the vertical spaces between the groups in the left column, but it doesn’t really matter.
The rest of the triangle comes from duplicating each group using LightBurn’s Grid Array tool with a convenient space between each copy. Make 15 copies of the top group for a total of 16 H000 and no copies of the bottom H337.
Hit Delete Duplicates to get rid of all the overlaid outer squares
If you’re fussy, Duplicate the line of blocks and move it up
Group each block individually to keep all the little squares together with the outline
Thusly:
Random Blocks – 16×16 – LightBurn combined layers
Combine each of those blocks with the sheet cutting template, tweak the binary sheet identification holes, and group the result:
Random Blocks – 16×16 – LightBurn cutting layouts
The leftmost block has All The Holes, the next one is missing a few, and so on across the line:
Random Blocks – 16×16 – LightBurn cutting layouts – detail
So the leftmost block corresponds to the black mask atop all the layers. Because it doesn’t have alignment holes in the corners or a binary sheet number, you get to align it by eyeball after gluing up the rest of the stack.
The rightmost block has no cutout squares at all and goes on the bottom of the stack. It also lacks a sheet number, but it’s easy to identify.
Set the LightBurn speed / power values for the layers to cut your stock of colored art paper.
Position the Letter Page Holder template to put the center of the sheet cutout at the center of the platform:
Random Blocks – 16×16 – LightBurn fixture template
Drop the fixture on the platform, use magnets to hold it down, then do a Print and Cut alignment on the corner targets so the template matches the fixture.
Then:
Click to select one of the blocks
Hit Ctrl-D to duplicate it
Hit P to slam it to the middle of the template
Hit Alt-S to Fire The Laser
Hit Del to delete the block
Iterate until done
I used a stack of paper in rainbow order roughly corresponding to the Inkscape layer colors, but you could stack them backwards or even use random colors and nobody would ever know:
Random Blocks – framed detail
I kinda like it, but wow that took a lot of prep work …