Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Tag: Improvements
Making the world a better place, one piece at a time
No snagging on a bulky quilt shoved through the machine
Not completely butt-ugly
Reasonably durable
I picked up reels of cool-white and warm-white waterproof LED strips (12 V, 3528-size chips, 5 m, 600 LED, 25 mm segments) from the usual eBay supplier, who promptly charged for both and shipped only the warm-white reel. Cool-white LEDs will be a better color match to daylight from the window and the little Ottlite she uses for detail work, but I ran some prototypes while we wait for the replacement.
The Chinese New Year really comes in handy as an excuse for screwing things up and not responding for a week or two. ‘Nuff said.
They’re similar to the RGB LEDs from a while ago, with even gummier “waterproof” encapsulation. I got double-density 600 LED strips to put more light emitters across the arm:
Various LED strip lights
The smaller 3528 SMD LEDs (vs. 5050 chips in the others) allow a narrower strip and the double-density layout means each three-LED segment is half as long long. The as-measured dimensions work out to:
25.0 mm segment length
8.2 mm strip width
2.5 mm thickness
The sealant thickness varies considerably, so I’d allow 3.0 mm for that in case it mattered. It slobbers over the edge of the strip here and there; allowing at least 9.0 mm would be wise.
The SMD resistor in each segment is 150 Ω. A 5 segment length drew 85 mA @ 12 V = 17 mA/segment. Boosting the voltage to 12.8 V got the current to the expected 100 mA = 20 mA/segment.
The LEDs are noticeably less bright than the 5050 LEDs, even at 20 mA/segment, but I think they’ll suffice for the task.
Removing the camera’s front cover (stick the screws to a length of masking tape!) reveals the backup battery hasn’t magically healed itself:
Casio EX-Z850 backup battery – corrosion
The main battery applies 3.2 V with the top terminal negative; it’s marked to help me remember that fact.
I snipped both legs of the top contact bracket, which promptly fell off, and then pushed the battery off its bottom contact. The condition of those two pads suggests a pair of cold solder joints (clicky for more dots):
Casio EX-Z850 backup battery – contact pads
I wanted to replace it with a polyacene supercap, but there’s just not enough room in there. The biggest cap that fit was a 33 μF 16 V SMD electrolytic cap, so I soldered one in place:
I had to flip the camera around to get the soldering iron in between the cap and what looks to be an intrusion monitoring switch just to its left. No lie, that shiny metal thing seems to be a tab that presses against the front cover; it could be a static discharge / grounding point, but the base looks more complex than that.
Now, a capacitor isn’t a battery, but memory backup doesn’t require much of a battery, either. I guesstimated the memory (or whatever) would draw a few microamps, at most, giving me a few seconds, at least, to swap batteries. A quick measurement shows that I’ll have plenty of time:
Casio EX-X850 backup capacitor – voltage vs time
The camera started up fine after that adventure, so the memory stays valid with the backup voltage down around 1 V.
The cap measured 34 μF, so a voltage decline of 24 mV/s works out to:
IC = C (dV/dT) = 34 μF x 24 mV/s = 820 nA
So, at least at room temperature, the memory draws less than a microamp.
I love it when a plan comes together!
With any luck, that capacitor should outlast the rest of the camera. It’ll definitely outlast a lithium battery, even if I could find one to fit in that spot.
I did those measurements by sampling the capacitor, rather than holding the meter probes in place, because the300 nA of current drawn by a 10 MΩ input resistance would cause a pretty large measurement error…
Cleaning up the wrecked gears on the can opener made it painfully obvious that I had to conjure at least one gear to get the poor thing working again:
Can opener – gears and cutters
Fortunately, those are more in the line of cogs, rather than real gears, so I decided a crude hack would suffice: drill a pattern of holes to define the openings between the teeth, file / grind the teeth reasonably smooth, and then tweak the shape to suit.
Fitting some small number-size drills between the remains of the teeth showed:
A #52 = 52.0 mil = 1.32 mm drill matched the root curvature
A #28 = 140.5 mil = 3.57 mm drill was tangent to the small drill and the tooth walls
Neither of those count as precision measurements, particularly given the ruined teeth, but they’re close enough for a first pass.
The OEM drive gear (on the right) has the teeth bent upward to mate with the cutter gear (on the left), but under normal gripping force, the teeth don’t mesh securely and tend to slide over / under / past each other. However, if I were to cut the drive gear from a metal sheet that’s thick enough to engage both the root and the crest of the cutter gear, that should prevent all the slipping & sliding. Some eyeballometric guesstimation suggested 2.5 mm would be about right and the Basement Laboratory Stockpile produced a small slab of 100 mil = 2.54 mm aluminum sheet.
However, the center part of the gear must have the same thickness as the OEM gear to keep the drive wheel at the same position relative to the cutter blade, which means a bit of pocket milling. I have some small ball burrs that seemed like they might come in handy.
A recent thread on the LinuxCNC mailing list announced Bertho Stultien’s gcmc, the G-Code Meta Compiler, and this looked like a golden opportunity to try it out. Basically, gcmc lets you write G-Code programs in a C-like language that eliminates nearly all the horrendous syntactic noise of raw G-Code. I like it a lot and you’ll be seeing more of it around here…
The gcmc source code, down below, include a function that handles automatic tool height probing, using that simple white-goods switch. The literal() function emits whatever you hand it as text for the G-Code file, which is how you mechanize esoteric commands that gcmc doesn’t include in its repertoire. It’s basically the same as my bare G-Code probe routine, but now maintains a state variable that eliminates the need for separate first-probe and subsequent-probe entry points.
One point that tripped me up, even though I should know better: because gcmc is a compiler, it can’t read G-Code parameters that exist only when LinuxCNC (or whatever) is interpreting the G-Code. You can write parameters with values computed at compile time, but you can’t read and process them in the gcmc program.
Anyhow, the first pass produced an array of holes that, as I fully expected, weren’t quite right:
Can opener gear – first hole pattern
The second pass got the root and middle holes tangent to each other:
Can opener gear – second hole pattern
It also ran a center drill pass for those tiny little holes to prevent their drill from wandering about. The other drills are about the same size as the center drill, so they’re on their own.
The rosette around the central hole comes from sweeping the burr in a dozen overlapping circles tangent to the outer diameter, then making a cleanup pass around the OD:
Can opener gear – 12 leaf rosette
Incidentally, that stray hole between the two patterns came from the aluminum sheet’s previous life, whatever it may have been. There are three other holes, two of which had flat washers taped to them, so your guess is as good as mine. That’s my story and I’m sticking with it.
Introducing the sheet to Mr Bandsaw and cutting through the outer ring produced a bizarre snowflake:
Can opener gear – cut out
Cutting off the outer ring of holes turned the incipient gear body into a ragged shuriken:
Can opener gear – isolated
A few minutes of increasingly deft Dremel cutoff wheel work, poised on the bench vise over the shopvac nozzle to capture the dust, produced a credible gear shape:
Can opener gear – first pass
Iterating through some trial fits, re-grinds, and general fiddling showed that the center pocket was too shallow. The cutter wheel should slightly clear the drive wheel, but it’s an interference fit:
Can opener gear – trial fit
Which, of course, meant that I had to clamp the [mumble] thing back in the Sherline and re-mill the pocket. The trick is to impale it on the wrong end of a suitable drill, clamp it down, and touch off that spot as the origin:
Can opener gear – re-centering
I took the opportunity to switch to a smaller ball and make 16 little circles to clear the pocket:
Can Opener Gear – 16 leaf rosette
Now that’s better:
Can opener gear – deeper pocket
Another trial fit showed that everything ended up in the right place:
Can opener gear – final fit
I gave it a few cranks, touched up any cogs that clashed with the (still misshapen) cutter gear, applied it to a randomly chosen can, and it worked perfectly:
Squeeze the levers to easily punch through the lid
Crankety crank on the handle, while experiencing none of the previous drama
The severed lid falls into the can
Which is exactly how it’s supposed to work. What’s so hard about that?
What you can’t see in that picture is the crest of the lowest cutter gear tooth fitting just above the bottom of the drive gear root. Similarly, the crest of the highest drive gear tooth remains slightly above the cutter root. That means the cutter gear teeth always engage the drive gear, there’s no slipping & sliding, and it’s all good.
Aluminum isn’t the right material for a gear-like object meshed with a steel counterpart, but it’s easy to machine on a Sherline. I’ll run off a few more for show-n-tell and, if when this one fails, I’ll have backup.
The gcmc source code:
// Can opener drive gears
// Ed Nisley KE4ZNU - February 2014
// Sherline CNC mill with tool height probe
// XYZ touchoff origin at center on fixture surface
DO_DRILLCENTER = 1;
DO_MILLCENTER = 1;
DO_DRILLINNER = 1;
DO_DRILLOUTER = 1;
DO_DRILLTIPS = 1;
//----------
// Overall dimensions
GearThick = 2.54; // overall gear thickness
GearCenterThick = 1.75; // thickness of gear center
GearTeeth = 12; // number of teeth!
ToothAngle = 360deg/GearTeeth;
GearOD = 22.0; // tooth tip
GearID = 13.25; // tooth root
SafeZ = 20.0; // guaranteed to clear clamps
TravelZ = GearThick + 1.0; // guaranteed to clear plate
//----------
// Tool height probe
// Sets G43.1 tool offset in G-Code, so our Z=0 coordinate always indicates the touchoff position
ProbeInit = 0; // 0 = not initialized, 1 = initialized
ProbeSpeed = 400.0mm;
ProbeRetract = 1.0mm;
PROBE_STAY = 0; // remain at probe station
PROBE_RESTORE = 1; // return to previous location after probe
function ProbeTool(RestorePos) {
local WhereWasI;
WhereWasI = position();
if (ProbeInit == 0) { // probe with existing tool to set Z=0 as touched off
ProbeInit++;
literal("#<_Probe_Speed> = ",to_none(ProbeSpeed),"\n");
literal("#<_Probe_Retract> = ",to_none(ProbeRetract),"\n");
literal("#<_ToolRefZ> = 0.0 \t; prepare for first probe\n");
ProbeTool(PROBE_STAY);
literal("#<_ToolRefZ> = #5063 \t; save touchoff probe point\n");
literal("G43.1 Z0.0 \t; set zero offset = initial touchoff\n");
}
elif (ProbeInit == 1) { // probe with new tool, adjust offset accordingly
literal("G49 \t; clear tool length comp\n");
literal("G30 \t; move over probe switch\n");
literal("G59.3 \t; use coord system 9\n");
literal("G38.2 Z0 F#<_Probe_Speed> \t; trip switch on the way down\n");
literal("G0 Z[#5063 + #<_Probe_Retract>] \t; back off the switch\n");
literal("G38.2 Z0 F[#<_Probe_Speed> / 10] \t; trip switch slowly\n");
literal("#<_ToolZ> = #5063 \t; save new tool length\n");
literal("G43.1 Z[#<_ToolZ> - #<_ToolRefZ>] \t; set new length\n");
literal("G54 \t; return to coord system 0\n");
literal("G30 \t; return to safe level\n");
}
else {
error("*** ProbeTool sees invalid ProbeInit: ",ProbeInit);
comment("debug,*** ProbeTool sees invalid ProbeInit: ",ProbeInit);
ProbeInit = 0;
}
if (RestorePos == PROBE_RESTORE) {
goto(WhereWasI);
}
}
//----------
// Utility functions
function WaitForContinue(MsgStr) {
comment(MsgStr);
pause();
}
function CueToolChange(MsgStr) {
literal("G0 Z" + SafeZ + "\n");
literal("G30\n");
WaitForContinue(MsgStr);
}
function ToolChange(Info,Name) {
CueToolChange("msg,Insert " + to_mm(Info[TOOL_DIA]) + " = " + to_in(Info[TOOL_DIA]) + " " + Name);
ProbeTool(PROBE_STAY);
WaitForContinue("msg,Set spindle to " + Info[TOOL_SPEED] + " rpm");
feedrate(Info[TOOL_FEED]);
}
function GetAir() {
goto([-,-,SafeZ]);
}
//-- compute drill speeds & feeds based on diameter
// rule of thumb is 100 x diameter at 3000 rpm for real milling machines
// my little Sherline's Z axis can't produce enough thrust for that!
MaxZFeed = 600.0mm; // fastest possible Z feed
TOOL_DIA = 0; // Indexes into DrillParam() result
TOOL_SPEED = 1; // spindle RPM
TOOL_FEED = 2; // linear feed
TOOL_TIP = 3; // length of 118 degreee drill tip
function DrillParam(Dia) {
local RPM,Feed,Tip,Data,Derating;
Derating = 0.25; // derate from (100 x diameter) max feed
RPM = 3000.0; // default 3 k rpm
Feed = Derating * (100.0 * Dia);
if (Feed > MaxZFeed) {
RPM *= (MaxZFeed / Feed); // scale speed downward to fit
Feed = MaxZFeed;
}
Tip = (Dia/2) * tan(90deg - 118deg/2);
Data = [Dia,RPM,Feed,Tip];
message("DrillParam: ",Data);
return Data;
}
//-- peck drilling cycle
function PeckDrill(Endpt,Retract,Peck) {
literal("G83 X",to_none(Endpt[0])," Y",to_none(Endpt[1])," Z",to_none(Endpt[2]),
" R",to_none(Retract)," Q",to_none(Peck),"\n");
}
//----------
// Make it happen
literal("G99\t; retract to R level, not previous Z\n");
WaitForContinue("msg,Verify: G30 position in G54 above tool change switch?");
WaitForContinue("msg,Verify: fixture origin XY touched off at center of gear?");
WaitForContinue("msg,Verify: Z touched off on top surface at " + GearThick + "?");
ProbeTool(PROBE_STAY);
//-- Drill center hole
if (DO_DRILLCENTER) {
DrillData = DrillParam(5.0mm);
ToolChange(DrillData,"drill");
goto([0,0,-]);
goto([-,-,TravelZ]);
drill([0,0,-1.5*DrillData[TOOL_TIP]],TravelZ,DrillData[TOOL_DIA]);
GetAir();
}
//-- Drill inner ring
if (DO_DRILLINNER) {
DrillData = DrillParam(1.32mm);
RingRadius = GearID/2.0 + DrillData[TOOL_DIA]/2.0; // center of inner ring holes
HolePosition = [RingRadius,0mm,-1.5*DrillData[TOOL_TIP]];
// but first, center-drill to prevent drifting
CDData = DrillParam(1.00mm); // pretend it's a little drill
CDData[TOOL_FEED] = 100mm; // ... use faster feed
CDPosition = HolePosition; // use center drill coordinates
CDPosition[2] = GearThick - 0.25mm; // ... just below surface
ToolChange(CDData,"center drill");
goto([0,0,-]);
goto([-,-,TravelZ]);
for (Tooth = 0 ; Tooth < GearTeeth ; Tooth++) {
drill(CDPosition,TravelZ,2*TravelZ); // large increment ensures one stroke
CDPosition = rotate_xy(CDPosition,ToothAngle);
}
// now drill the holes
ToolChange(DrillData,"drill");
goto([0,0,-]);
goto([-,-,TravelZ]);
for (Tooth = 0 ; Tooth < GearTeeth ; Tooth++) {
PeckDrill(HolePosition,TravelZ,DrillData[TOOL_DIA]);
HolePosition = rotate_xy(HolePosition,ToothAngle);
}
GetAir();
}
//-- Mill center recess
if (DO_MILLCENTER) {
MillData = [4.50mm,3000,250.0mm,0.0mm]; // spherical ball burr
Delta = GearThick - GearCenterThick; // depth to be milled away
Inset = sqrt(2.0*Delta*(MillData[TOOL_DIA]/2) - pow(Delta,2)); // toll axis to milled edge
ToolChange(MillData,"ball burr");
goto([0,0,-]); // above central hole
goto([0,0,GearThick]); // vertically down to flush with surface
move([0,0,GearCenterThick]); // into gear blank
for (Angle = 0.0deg; Angle < 360.0deg; Angle+=360.0deg/16) { // clear interior
circle_cw((GearID/2 - Inset)/2,Angle);
}
move_r([(GearID/2 - Inset),0.0,0.0]); // clean rim
circle_ccw([0.0,0.0,GearCenterThick],2);
GetAir();
}
//-- Drill outer ring
if (DO_DRILLOUTER) {
RingRadius += DrillData[TOOL_DIA]/2; // at OD of inner ring holes
DrillData = DrillParam(3.18mm);
RingRadius += DrillData[TOOL_DIA]/2.0; // center of outer ring holes
HolePosition = [RingRadius,0mm,-1.5*DrillData[TOOL_TIP]];
ToolChange(DrillData,"drill");
for (Tooth = 0 ; Tooth < GearTeeth ; Tooth++) {
PeckDrill(HolePosition,TravelZ,DrillData[TOOL_DIA]);
HolePosition = rotate_xy(HolePosition,ToothAngle);
}
GetAir();
}
//-- Drill to locate gear tooth tip end
if (DO_DRILLTIPS) {
DrillData = DrillParam(4.22mm);
RingRadius = GearOD/2.0 + DrillData[TOOL_DIA]/2.0; // tangent to gear tooth tip
HolePosition = [RingRadius,0mm,-1.5*DrillData[TOOL_TIP]];
HolePosition = rotate_xy(HolePosition,ToothAngle/2); // align to tooth
ToolChange(DrillData,"drill");
for (Tooth = 0 ; Tooth < GearTeeth ; Tooth++) {
PeckDrill(HolePosition,TravelZ,DrillData[TOOL_DIA]);
HolePosition = rotate_xy(HolePosition,ToothAngle);
}
GetAir();
}
literal("G30\n");
comment("msg,Done!");
The original doodle that suggested the possibility:
Can Opener Gears – Doodle 1
The chord equation at the bottom shows how to calculate the offset for the ball burr, although it turns out there’s no good way to measure the cutting diameter of the burr and it’s not really spherical anyway.
A more detailed doodle with the key line at a totally bogus angle:
Can Opener Gears – Doodle 2
The diagram in the lower right corner shows how you figure the length of the tip on a 118° drill point, which you add to the thickness of the plate in order to get a clean hole.
Mary wants more light directly around the needle of her Kenmore Model 158 sewing machine, as the existing light (a 120 V 15 W incandescent bulb tucked inside the end housing) casts more of a diffuse glow than a directed beam:
Kenmore Model 158 Sewing Machine – lamp
The end cap fits snugly around the bulb, but I thought a pair of 10 mm white LEDs, mounted side-by-side and aimed downward at the cover plate, would work. Of course, plugging a pair of white LEDs into a 120 VAC socket won’t work, but some judicious rewiring and a new 12 V DC wall wart will take care of that.
The bulb has a dual-contact bayonet base, with both pins isolated from the shell and connected to the non-polarized (!) line cord through the power switch. I didn’t know it was called a BA15d base, but now I do.
A 12 V automotive brake/taillight bulb (type 1157, I think) pulled from the Big Box o’ Bulbs has a slightly different pin arrangement that keys the filaments (which are not isolated from the shell) to the surrounding reflector:
BA15d Bayonet Bulb Bases – 120V vs. 12V pins
So I conjured a mockup to see if it would fit, using 2-56 screws to mimic whatever hardware might be practical:
BA15d Bulb – LED Adapter
The solid model shows how it all fits together:
Sears Lamp LED Adapter – Show view
The two tiny ruby-red pins represent filament snippets in alignment holes, barely visible in real life:
It actually fit pretty well, ignoring the fact that the LEDs point 90° from the intended direction (so I could see how the holes came out inside the pivot, honest), and lit up the area quite well, but it’s such a delicate affair that removing the entire socket and replacing it with a dedicated metal bracket / heatsink for two high-power SMD LEDs will be better.
The OpenSCAD source code:
// Adapter for LEDs in Sears sewing machine lamp socket
// Ed Nisley - KE4ZNU - January 2014
Layout = "Show"; // Build Show LEDTab LEDPlate ShellMount
//- Extrusion parameters must match reality!
// Print with 2 shells and 3 solid layers
ThreadThick = 0.20;
ThreadWidth = 0.40;
HoleWindage = 0.2; // extra clearance
Protrusion = 0.1; // make holes end cleanly
Gap = 2.0; // spacing between Show parts
AlignPinOD = 1.70; // assembly alignment pins: filament dia
inch = 25.4;
//----------------------
// Dimensions
//-- LED mounting plate
LEDDia = 10.0; // LED case OD
LEDFlangeOD = 10.7;
LEDPlateThick = 2.0; // mounting plate thickness
LEDMargin = 2.0;
LEDSpaceOC = LEDDia + LEDMargin; // LED center-to-center distance (single margin between!)
LEDTabLength = 15.0; // base to screw hole center
LEDTabThick = 4.0; // tab with hole for mounting screw
LEDTabScrewOD = 2.0;
LEDTabWidth = (3.0*2) + LEDTabScrewOD;
LEDMountHeight = 25.0; // estimated mounting screw centerline to bottom of LEDs
//-- Lamp base adapter
// hard inch dimensions!
ShellOD = 0.600 * inch; // dia of metallic shell
ShellOAL = 0.66 * inch; // ... total length
ShellInsert = 7/16 * inch; // ... length engaging socket
ShellSides = 4*4;
BulbOD = 0.75 * inch; // glass bulb
BulbLength = 1.14 * inch;
InsulOD = 0.485 * inch; // insulating stub around contact pins
InsulThick = 0.070 * inch; // ... beyond end of shell
ContactOD = 2.0; // contact holes through base (not heads)
ContactOC = 0.300 * inch; // ... center-to-center spacing
BayonetOD = 0.080 * inch; // bayonet pin diameter
BayonetOffset = 0.125 * inch; // from end of metal base
LampOAL = InsulThick + ShellOAL + BulbLength;
echo(str("Overall Length: ",LampOAL));
//-- Miscellany
//----------------------
// 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) {
Range = floor(50 / Space);
for (x=[-Range:Range])
for (y=[-Range:Range])
translate([x*Space,y*Space,Size/2])
%cube(Size,center=true);
}
//-- Tab for screw mounting LED holder
// AddLength remains below Z=0 for good union
module LEDTab() {
difference() {
linear_extrude(height=LEDTabThick)
hull() {
circle(d=LEDTabWidth);
translate([LEDTabLength/2,0,0])
square([LEDTabLength,LEDTabWidth],center=true);
}
translate([0,0,-Protrusion])
rotate(180/6)
PolyCyl(LEDTabScrewOD,(LEDTabThick + 2*Protrusion),6);
for (i=[-1,1])
translate([LEDTabLength/2,i*LEDTabWidth/4,LEDTabThick/2])
rotate([0,90,0]) rotate(180/4)
PolyCyl(AlignPinOD,(LEDTabLength/2 + Protrusion),4);
}
}
//-- Plate holding LEDs
module LEDPlate() {
difference() {
union() {
linear_extrude(height=LEDPlateThick)
hull() {
for (i=[-1,1])
translate([i*LEDSpaceOC/2,0,0])
circle(d=(LEDDia + 2*LEDMargin));
translate([0,(LEDFlangeOD/2 + LEDTabWidth/2),0])
square([LEDTabThick,LEDTabWidth],center=true);
}
}
for (i=[-1,1])
translate([i*LEDSpaceOC/2,0,-Protrusion])
rotate(180/12)
PolyCyl(LEDDia,(LEDPlateThick + 2*Protrusion),12);
for (i=[-1,1])
translate([0,(i*LEDTabWidth/4 + LEDFlangeOD/2 + LEDTabWidth/2),3*ThreadThick]) rotate(180/4)
PolyCyl(AlignPinOD,(LEDTabLength/2 + Protrusion),4);
}
}
//-- Bulb shell mounting adapter
module ShellMount() {
difference() {
union() {
cylinder(r1=InsulOD/2,r2=ShellOD/2,h=(InsulThick + Protrusion),$fn=ShellSides);
translate([0,0,InsulThick])
cylinder(r=ShellOD/2,h=(LampOAL - LEDMountHeight + LEDTabWidth/2),$fn=ShellSides);
}
translate([0,ShellOD,(InsulThick + BayonetOffset)]) // bayonet pin hole
rotate([90,0,0]) rotate(180/4)
PolyCyl(BayonetOD,2*ShellOD,4);
translate([0,ShellOD,(InsulThick + LampOAL - LEDMountHeight)]) // LED mount screw hole
rotate([90,0,0])
PolyCyl(LEDTabScrewOD,2*BulbOD,6);
translate([0,0,(InsulThick + ShellOAL + LampOAL/2)]) // slot for LEDTab mount
cube([2*ShellOD,(LEDTabThick + 2*Protrusion),LampOAL],center=true);
for (i=[-1,1]) // contact pin holes
translate([i*ContactOC/2,0,-Protrusion])
rotate(180/6)
PolyCyl(ContactOD,2*LampOAL,6);
}
}
//- Build it
ShowPegGrid();
if (Layout == "LEDTab")
LEDTab();
if (Layout == "LEDPlate")
LEDPlate();
if (Layout == "ShellMount")
ShellMount();
if (Layout == "Show") {
LEDPlate();
translate([-LEDTabThick/2,(LEDFlangeOD/2 + LEDTabWidth/2),(LEDTabLength + LEDPlateThick + Gap)])
rotate([0,90,0])
LEDTab();
for (i=[-1,1])
# translate([0,(i*LEDTabWidth/4 + LEDFlangeOD/2 + LEDTabWidth/2),(LEDPlateThick + Gap/4)])
rotate(180/4)
cylinder(r=AlignPinOD/2,h=Gap/1,$fn=4); // fake the pins
translate([0,(LEDFlangeOD/2 + LEDTabWidth/2),(LampOAL - LEDTabWidth/2)])
rotate([0,180,0]) rotate(90)
ShellMount();
}
if (Layout == "Build") {
translate([0,LEDDia,0])
LEDPlate();
translate([-10,-(LEDMargin + LEDTabWidth),0])
rotate(-90)
LEDTab();
translate([10,-(LEDMargin + LEDTabWidth),0])
ShellMount();
}
The original doodles for the bulb dimensions and adapter layout:
It turns out that the audio-over-HDMI/DisplayPort channel which, for whatever reason, is the only way to get audio out of the Optiplex 980 with the big Dell U2711 monitor starts up AT MAXIMUM VOLUME! regardless of the GUI’s Pulseaudio mixer setting that’s diligently saved-and-restored across sessions. That makes a certain perverse sense, as the digital-to-analog converter & power amp live inside the monitor.
Manually adjusting the GUI mixer by one click, either up or down, forces the new setting out over the digital link to the monitor, after which the audio output corresponds to the mixer; I never remember that until just after some dipshit auto-play video lights up with a fanfare.
Setting the mixer to the same value doesn’t force an update, so the obvious solution (at least to me) of sending a fixed initial value doesn’t work; it’s optimized away. I think that’s why the initial update doesn’t happen: the stored volume is the same as the, ah, stored volume, so there’s no need to tell the monitor.
The automatic solution involves putting two more commands in my ever-growing ~/.config/startup.sh:
That sets a rational level (which might be the same as the existing one from the previous session), then changing it by one tiny click to force the new value out to the monitor.
The strut supporting the two drawers in the bottom of the refrigerator came out in two pieces during a recent cleaning session. To judge from the condition of the joint, I’d done this once before in its history:
Refrigerator strut – tab clamps
That tab inserts into a slot in the front of the elaborate frame that supports the drawers, where it’s captured by a metal bar. Should you lift the rear of the strut without first removing the bar, the tab snaps off at the base. I’ve annotated the top of the strut in the hopes of reminding me the next time around.
A pair of bumps at the front of the drawer guides should hold the drawers closed, but it’s pretty obvious that’s not working as intended:
Refrigerator strut – worn retainers
I shaped strips of phosphor bronze spring stock around the bumps:
Refrigerator strut – phosphor bronze covers – top
The bottom view shows they’re held in place by crimps and a generous dollop of faith:
That should serve until I know whether the plastic drawer rail will carve through the metal. The drawers slide out with much more enthusiasm now, so it’s a Good Thing until something else breaks.
Yes, this is the refrigerator with the Freezer Dog…