The Smell of Molten Projects in the Morning

Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.

Author: Ed

  • 3D Printing Show-n-Tell

    So the local hackerspace put on a show in Highland and, being the guy with the 3D printer, I volunteered for a few hours of stand-up comedy.

    A pile of stuff provided talking points:

    3D Printing This Way - with clutter
    3D Printing This Way – with clutter

    Four pages of solid model images on nice glossy photo paper let me talk about what must happen before the plastic emerges:

    I loves me some OpenSCAD modeling, yes, I do…

    Signage festooned with sample critters dragged ’em in off the street:

    3D Printing This Way - signs on post
    3D Printing This Way – signs on post

    The printer produced a steady stream of tiny owls:

    M2 - Mini owl on platform
    M2 – Mini owl on platform

    And the ever-popular whistle:

    M2 - Whistle on platform
    M2 – Whistle on platform

    A good time was had by all!

  • LED Output vs. Current: Efficiency Loss

    Some data points from that circuit produced this graph:

    LED Output vs Current
    LED Output vs Current

    Relative to the output at 5 mA, the efficiency drops off pretty much linearly:

    LED Efficiency vs Current
    LED Efficiency vs Current

    That’s computed as the ratio of the actual light output to the output at 5 mA scaled by the current ratio.

    So putting the screws to the LEDs does produce more light, but not quite as much as you’d expect. Above maybe 40 mA, it’s not worth the effort.

    Now we know…

     

  • LED Driver + Zero-bias Photodiode Amplifier

    This may come in handy for something, like measuring LED output:

    LED Output Tester - Schematic
    LED Output Tester – Schematic

    The LM324 converts the input voltage to an LED drive current, scaled by the sense resistor and the gain of IC2B to 25 mA/V. The feedback loop closes through the MOSFET and C6 rolls off the response, so there’s a nasty overshoot on the leading edge of input pulses where the current increases faster than the op amp can tamp it down:

    Red LED - 25 mA 14 uA
    Red LED – 25 mA 14 uA

    The LM356 acts as a transimpedance amplifer to convert the photodiode current to voltage. The PIN-10AP specs say it should operate in photovoltaic mode with zero bias and that more than -3V of bias will kill the photodiode; the LM356 should hold its inverting input at virtual ground, but the two 1N5819 Schottky diodes enforce that limit. There being zero volts across the diodes, they don’t leak in either direction, so it’s all good.

    The circuit is an embarrassing hairball on solderless breadboard, so use your imagination…

    You could mash this together with the LED Curve Tracer, although you’d want better low-current resolution from the Arduino output.

  • One Problem With Electronic Medical Records

    This seems innocent enough:

    Medical eRecord Security
    Medical eRecord Security

    Of course, that laptop:

    • Runs Windows
    • Has unused USB and Firewire ports
    • Has active WiFi networking
    • Doesn’t have a screensaver timeout
    • Was left alone with a patient
    • Is not locked

    I mentioned to my doctor that, if I were of malign intent, I would now have complete control of every PC on their network. That didn’t make much of an impression, as the same thing happened on my next visit.

    Of course, moving to electronic records makes a lot of sense, but if you think they’ll be any more secure than any other online personal information, you’re wrong.

  • Garden Sprayer: End of Life

    The hose attached to this garden sprayer had failed last season, but the hose fitting had become one with the sprayer. Soaking it with penetrating oil for far longer than seemed necessary didn’t help, so I tried brute force:

    Garden sprayer hose fitting
    Garden sprayer hose fitting

    After convincing myself that wasn’t going to work, I cut the fitting off and tried the old standby of collapsing the threaded shell inward with a small punch:

    Garden sprayer - rolled-in fitting
    Garden sprayer – rolled-in fitting

    That didn’t work, either: the shell really had become one with the sprayer.

    As it turned out, the plastic sprayer body had begun to crack in several high-stress locations and would shortly become Yet Another Project. I cut my losses and tossed the hose and the sprayer.

  • LED + Photodiode: Verifying Linearity

    Given that test fixture, the obvious question is whether the PIN-10AP photodiode’s output current varies linearly with light intensity, just like the specs would lead you to believe. I excavated the sheet of 2-stop neutral density filter gel from the Parts Warehouse Wing and cut some 30 mm disks:

    LED Photodiode test fixture - ND filter disks
    LED Photodiode test fixture – ND filter disks

    A single filter layer should reduce the light intensity by 2 f/stops = a factor of 4. Each successive layer reduces the intensity by another factor of 4. They’re all at least reasonably clean and free of defects, but they’re definitely not optical lens quality.

    Running the LED with a 100 mA pulse at 20% duty cycle and stacking the disks in the fixture, one by one, between the LED and photodiode, produces this data:

    Layers Attenuation Scale V I – uA Ratio
    0 1 1.0000 8.7 87  
    1 4 0.2500 1.9 19 4.58
    2 16 0.0625 0.43 4.3 4.42
    3 64 0.0156 0.097 0.97 4.43
    4 256 0.0039 0.022 0.22 4.41

    The Ratio column divides successive pairs of current values. The first step, from “no filter” to “one filter”, came out a bit larger than the rest, probably because the gel sheet isn’t anti-reflective and some light bounces off the top.

    After that, though, it looks just like I’m cheating, doesn’t it?

    The ratios should be 4.0, but the actual 4.4 means it’s a 2.1 stop filter. Close enough, methinks.

  • LED + Photodiode Test Fixture

    An upcoming Circuit Cellar column calls for a way to measure LED light output vs. current input, which means I need some way to hold LEDs directly over a photodiode while excluding ambient light. Fortunately, the M2 had black PLA filament already loaded:

    LED Photocell Fixture - parts
    LED Photocell Fixture – parts

    That honkin’ big photodiode is a surplus PIN-10AP that’s been lying in wait for an opportunity just like this. The green filter matches the silicon response to CIE-standard human eye sensitivity, so the output tracks what you’d actually see. That’s irrelevant for testing red LEDs that all have pretty much the same wavelength, but it might come in handy for something.

    The main body of the fixture holds the LED about 1 mm from the front of the photodiode, indexed against the LED flange so they’re all at a consistent location. The cap has three locating pins made of 3 mm orange filament, with black foam rubber to push the LED into position and block ambient light.

    The business end looks like this:

    LED Photocell Fixture - LED view
    LED Photocell Fixture – LED view

    The most convenient way to mount the thing involves a right-angle BNC adapter in my trusty bench vise:

    LED Photocell Fixture - with breadboard
    LED Photocell Fixture – with breadboard

    The circuitry has a voltage-to-current driver for the LED and a zero-bias current-to-voltage converter for the photocell. The zero-bias trick keeps the voltage across the photodiode at zero, so the current varies linearly with illumination.

    The solid model laid out for printing along the X axis:

    LED Fixture for PIN-10AP Photodiode - solid model overview
    LED Fixture for PIN-10AP Photodiode – solid model overview

    It obviously has some improvements over the as-printed one in the pictures, in the unlikely event I need another fixture. The most important: a rear ring covering the back of the photodiode. Turns out that the PIN-10AP filter cap leaks a surprising amount of light around the body; I covered the gap with black tape to make the measurements, but that’s crude.

    I added a few screw holes to hold the parts together, but the cap (with the foam and pegs) must come off easily while swapping LEDs. I’d be tempted to sink studs into the body and use wing nuts to hold the lid in place, but I don’t have any 4-40 wing nuts…

    There’s a tiny bit of support under the central hole to support the LED flange recess and the trench for some foam under the leads:

    LED Fixture for PIN-10AP Photodiode - support
    LED Fixture for PIN-10AP Photodiode – support

    That’s another improvement; the as-printed one has foam on only one side of the leads.

    The OpenSCAD source code:

    // LED test fixture for PIN-10AP photodiode
    // Ed Nisley KE4ZNU May 2013
    
    // Layouts: Adapter AdapterSupport Cap Shield Build Show
    
    Layout = "Build";
    
    Gap = 8;		// between parts in Show
    
    //- Extrusion parameters must match reality!
    //  Print with +1 shells and 3 solid layers
    
    ThreadThick = 0.25;
    ThreadWidth = 0.40;
    
    HoleWindage = 0.2;
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1;			// make holes end cleanly
    
    Spacing = 5;				// between parts on build platform
    
    inch = 25.4;
    
    Tap2_56 = 0.070 * inch;
    Clear2_56 = 0.082 * inch;
    Head2_56 = 0.156 * inch;
    Head2_56Thick = 0.055 * inch;
    
    //----------------------
    // Dimensions
    
    PhotoDiodeOD = 31.3;
    PhotoDiodeStemOD = 16.0;
    PhotoDiodeStemLength = 8.0;
    PhotoDiodeWindowDia = 17.7;
    PhotoDiodeHeight = 14.0;
    
    FixtureOD = PhotoDiodeOD + 2*7.0;
    
    LEDDia = 5.0;				// LED body
    LEDFlangeOD = 6.0;			// flange at base of LED
    LEDFlangeThick = IntegerMultiple(1.5,ThreadThick);
    LEDLength = 10.0;			// overall length
    LEDRecess = 4.0;			// tube to fit LED body
    LEDSides = 8;
    
    FixtureLength = PhotoDiodeHeight + LEDLength + IntegerMultiple(1.0,ThreadThick);
    
    CapLength = 15.0;			// LED cover
    
    FoamOD = FixtureOD/2;
    FoamThick = IntegerMultiple(2.0,ThreadThick);
    
    TrenchDepth = 2*FoamThick;
    TrenchWidth = LEDDia;
    
    ShieldThick = 5.0;
    ShieldScrewCircle = PhotoDiodeOD + (FixtureOD - PhotoDiodeOD)/2;
    
    PinOD = 3.0;				// alignment pin (filament)
    PinLength = 10.0;			//   ... total length
    PinCircle = FixtureOD/2;
    
    GrubScrewOD = Tap2_56;
    
    $fn=4*6;					// default cylinder sides
    
    //----------------------
    // 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(95 / Space);
      RangeY = floor(125 / Space);
    
    	for (x=[-RangeX:RangeX])
    	  for (y=[-RangeY:RangeY])
    		translate([x*Space,y*Space,Size/2])
    		  %cube(Size,center=true);
    
    }
    
    //-----------------------
    // Parts
    
    module Adapter() {
    
    	difference() {
    		cylinder(r=FixtureOD/2,h=FixtureLength);
    		translate([0,0,-Protrusion]) {
    			PolyCyl(LEDDia,2*FixtureLength,LEDSides);
    			PolyCyl(PhotoDiodeWindowDia,(FixtureLength - LEDRecess + Protrusion));
    			PolyCyl(PhotoDiodeOD,(PhotoDiodeHeight + Protrusion));
    		}
    		translate([0,0,(FixtureLength - LEDFlangeThick)])
    			PolyCyl(LEDFlangeOD,2*LEDFlangeThick,LEDSides);
    		translate([FixtureOD/2,0,(FixtureLength + FoamThick/2 - LEDFlangeThick)]) {
    			cube([FixtureOD,TrenchWidth,FoamThick],center=true);
    		}
    		for (angle = [90:90:270])
    			rotate(angle)
    				translate([0.75*PinCircle,0,(FixtureLength - PinLength/2)])
    					PolyCyl(PinOD,PinLength,6);
    		for (angle = [0:120:240])
    			rotate(angle)
    				translate([ShieldScrewCircle/2,0,-Protrusion])
    					rotate(45)
    						PolyCyl(Tap2_56,(ShieldThick - 6*ThreadThick + Protrusion));
    		if (0)
    			translate([0,0,FixtureLength/4])
    				rotate([0,90,0])
    					PolyCyl(GrubScrewOD,FixtureOD);
    	}
    
    }
    
    module AdapterSupport() {
    
    spiderthick = IntegerMultiple(LEDFlangeThick - ThreadThick,ThreadThick);
    
    	color("Yellow")
    		union() {
    			for (leg = [0:LEDSides/2 - 1])
    				rotate(leg*360/LEDSides)
    					translate([0,0,spiderthick/2])
    					cube([(LEDFlangeOD - 0.5*ThreadWidth),
    							2.5*ThreadWidth,
    							spiderthick],
    							center=true);
    			cylinder(r=LEDDia/2,h=spiderthick,$fn=LEDSides);
    			for (bar = [-1:1])
    				translate([LEDDia/3,(bar*3*ThreadWidth - ThreadWidth),0])
    					cube([FixtureOD/2,2*ThreadWidth,IntegerMultiple(LEDFlangeThick - ThreadThick)]);
    		}
    }
    
    module Cap() {
    
    	difference() {
    		cylinder(r=FixtureOD/2,h=CapLength);
    		translate([(FixtureOD/2 - LEDDia/2),0,CapLength]) {
    			cube([FixtureOD,TrenchWidth,2*TrenchDepth],center=true);
    		}
    		translate([0,0,(CapLength - FoamThick)])
    			PolyCyl(FoamOD,(FoamThick + Protrusion));
    		for (angle = [90:90:270])
    			rotate(angle)
    				translate([0.75*PinCircle,0,(CapLength - PinLength/2)])
    					PolyCyl(PinOD,PinLength,6);
    	}
    
    }
    
    module Shield() {
    
    	difference() {
    		cylinder(r=FixtureOD/2,h=ShieldThick);
    		translate([0,0,-Protrusion])
    			PolyCyl(PhotoDiodeStemOD,(ShieldThick + 2*Protrusion));
    		for (angle = [0:120:240])
    			rotate(angle) {
    				translate([ShieldScrewCircle/2,0,-Protrusion])
    					rotate(180/5)
    						PolyCyl(Clear2_56,(ShieldThick + 2*Protrusion));
    				if (0)
    				translate([ShieldScrewCircle/2,0,(ShieldThick - 1.5*Head2_56Thick)])
    					rotate(180/6)
    						PolyCyl(Head2_56,4*Head2_56Thick);
    			}
    	}
    }
    
    //-------------------
    // Build it...
    
    ShowPegGrid();
    
    if (Layout == "Adapter")
    	Adapter();
    
    if (Layout == "Cap")
    	Cap();
    
    if (Layout == "Shield")
    	Shield();
    
    if (Layout == "Show") {
    	translate([0,0,(ShieldThick + Gap)]) {
    		translate([0,0,FixtureLength + CapLength + Gap])
    			rotate([180,0,0])
    				Cap();
    		Adapter();
    
    		color("Orange")
    		for (angle = [90:90:270])
    			rotate(angle)
    				translate([0.75*PinCircle,0,(FixtureLength + Gap - PinLength/2)])
    					PolyCyl(PinOD,PinLength,6);
    	}
    
    	Shield();
    }
    
    	if (Layout == "AdapterSupport") {
    	translate([0,0,FixtureLength])
    		rotate([180,0,0])
    			%Adapter();
    	AdapterSupport();
    }
    
    if (Layout == "Build") {
    	translate([(Spacing + FixtureOD),0,0]) {
    		translate([0,0,FixtureLength])
    			rotate([180,0,0])
    				Adapter();
    		AdapterSupport();
    	}
    	translate([0,0,0])
    		Cap();
    
    	translate([-(Spacing + FixtureOD),0,0])
    		Shield();
    }