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.

Category: Machine Shop

Mechanical widgetry

  • Longboard Ground Effect Lighting Case

    Our Larval Engineer has been diligently procrastinating on her summer project to add ground effect lighting to her longboard. I’m hereby depriving her of the opportunity to learn enough OpenSCAD to build a case from scratch:

    Longboard Ground Effect Lighting Case - exploded view
    Longboard Ground Effect Lighting Case – exploded view

    This is upside-down from its in-use position, but she’ll have it in this orientation on the bench. Four 10-32 screws clamp the whole affair together and hold it to a bottom aluminum plate with threads to suit; that plate also gets bolted between the longboard and the rear truck.

    The general idea is that four 2 A·h lithium prismatic cells live in the bottom slice with their protection circuit, sandwiched between two aluminum plates that should protect them from all but catastrophic impact. The circuit board (which ought to be a PCB, but we’ll go with hand wiring for the first iteration) gets clamped in the recess between the two upper slices, above the upper aluminum plate. A polycarbonate sheet on top provides visibility for the Arduino blinky LED inside and shows off the circuitry to one and all.

    I think a ridge on each long wall should suffice to hold the cells against the end wall; we don’t have the cells in hand to figure that out yet. She gets to add internal partitions, cable cutouts, and suchlike.

    Oh. “Ground effect lighting” means ten RGB LED strips glued under the longboard deck. Her innovation is to make the LED color depend on the speed, which can range upward to scary-fast. It’s a simple matter of software, using a Hall effect sensor for input. This will look much better after dark, but she’s pretty much nocturnal anyway.

    The OpenSCAD source code:

    // Longboard Ground Effect Lighting Controller Case
    // Ed Nisley KE4ZNU
    // Karen Nisley KC2SYU
    // July 2012
    
    // Layout options
    
    Layout = "Show";
     // Overall layout: Fit Show
     // Printing plates: Build1 .. Buildn (see bottom!)
     // Parts: BatteryLayer PCBLayer1 PCBLayer2
     // Shapes: CaseShell PCBEnvelope
    
    ShowGap = 5; // spacing between parts in Show layout
    
    //-----
    // Extrusion parameters must match reality!
    
    ThreadThick = 0.25;
    ThreadWidth = 2.0 * ThreadThick;
    
    HoleWindage = 0.2;
    
    //-- Handy stuff
    
    function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
    
    Protrusion = 0.1; // make holes end cleanly
    
    inch = 25.4;
    
    Tap10_32 = 0.159 * inch;
    Clear10_32 = 0.190 * inch;
    Head10_32 = 0.373 * inch;
    Head10_32Thick = 0.110 * inch;
    Nut10_32Dia = 0.433 * inch;
    Nut10_32Thick = 0.130 * inch;
    Washer10_32OD = 0.381 * inch;
    Washer10_32ID = 0.204 * inch;
    
    //----------------------
    // Dimensions
    
    CellWidth = 50.0; // Lithium-ion cell dimensions
    CellLength = 60.0;
    CellThick = 6.0;
    CellClearance = 1.5; // on all sides
    CellTabClearance = 10.0; // for connections
    
    BatteryCount = 4; // cells in the battery
    BatteryHeight = BatteryCount*CellThick + 2*CellClearance;
    
    PCMWidth = 16.0; // Battery protection board
    PCMLength = 50.0;
    PCMThick = 4.0; // at terminal end of cells
    
    PillarOD = Washer10_32OD + 2*0.5; // screw pillar diameter
    PillarOffset = (PillarOD/2) / sqrt(2.0); // distance to case inside corner
    
    WallThick = 6.0; // case wall thickness
    
    PinOD = 1.4; // alignment pin size
    
    CaseOALength = CellLength + CellClearance + CellTabClearance + PCMThick + 2*WallThick;
    CaseInsideLength = CaseOALength - 2*WallThick;
    echo("Box Length outside: ",CaseOALength);
    echo(" inside: ",CaseInsideLength);
    
    CaseOAWidth = CellWidth + 2*CellClearance + 2*WallThick;
    CaseInsideWidth = CaseOAWidth - 2*WallThick;
    echo("Box Width outside: ",CaseOAWidth);
    echo(" inside: ",CaseInsideWidth);
    
    CaseOAHeight = BatteryCount * CellThick + CellClearance;
    
    PCBThick = 1.0; // PCB thickness
    PCBMargin = 3.0; // clamping margin around PCB edge
    PartHeight = 10.0; // height of components above PCB
    WiringThick = 4.0; // wiring below PCB
    
    echo("PCB thickness:",PCBThick);
    echo(" clamp margin: ",PCBMargin);
    echo(" wiring: ",WiringThick);
    echo(" components: ",PartHeight);
    
    PCBLayer1Thick = IntegerMultiple(WiringThick + PCBThick/2,ThreadThick);
    PCBLayer2Thick = IntegerMultiple(PartHeight + PCBThick/2,ThreadThick);
    
    echo("Battery compartment height: ",BatteryHeight);
    echo("PCB Layer 1 height: ",PCBLayer1Thick);
    echo("PCB Layer 2 height: ",PCBLayer2Thick);
    
    PlateThick = 1/16 * inch; // aluminum mount / armor plates
    
    echo("Total height: ",2*PlateThick + BatteryHeight + PCBLayer1Thick + PCBLayer2Thick);
    
    //----------------------
    // 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);
    
    }
    //-------------------
    // Shapes
    
    module CaseShell(h=1.0) {
    
    difference() {
     union() {
     translate([0,0,h/2])
     cube([CaseOALength,CaseOAWidth,h],center=true);
    
    for (x=[-1,1])
     for (y=[-1,1])
     translate([x*(PillarOffset + CaseInsideLength/2),
     y*(PillarOffset + CaseInsideWidth/2),
     h/2])
     cylinder(r=PillarOD/2,h,center=true,$fn=4*6);
     }
    
    for (x=[-1,1]) // screw holes on corners
     for (y=[-1,1])
     translate([x*(PillarOffset + CaseInsideLength/2),
     y*(PillarOffset + CaseInsideWidth/2),
     -Protrusion])
     PolyCyl(Clear10_32,(h + 2*Protrusion),8);
    
    for (x=[-1,1]) // alignment pins in width walls
     translate([x*(CaseOALength - WallThick)/2,0,-Protrusion])
     rotate(45)
     PolyCyl(PinOD,(h + 2*Protrusion));
     for (y=[-1,1]) // alignment pins in length walls
     translate([0,y*(CaseOAWidth - WallThick)/2,-Protrusion])
     rotate(45)
     PolyCyl(PinOD,(h + 2*Protrusion));
    
    }
    }
    
    module BatteryLayer() {
    
    difference() {
     CaseShell(BatteryHeight);
    
    translate([0,0,BatteryHeight/2])
     cube([CaseOALength - 2*WallThick,
     CaseOAWidth - 2*WallThick,
     BatteryHeight + 2*Protrusion],
     center=true);
     }
    }
    
    module PCBEnvelope() {
    
    union() {
     translate([0,0,WiringThick + PCBThick + PartHeight/2])
     cube([CaseInsideLength - 2*PCBMargin,
     CaseInsideWidth - 2*PCBMargin,
     PartHeight + 2*Protrusion],
     center=true);
    
    translate([0,0,WiringThick + PCBThick/2])
     cube([CaseInsideLength,CaseInsideWidth,PCBThick],center=true);
    
    translate([0,0,WiringThick/2])
     cube([CaseInsideLength - 2*PCBMargin,
     CaseInsideWidth - 2*PCBMargin,
     WiringThick + 2*Protrusion],
     center=true);
     }
    }
    
    module PCBLayer1() {
    
    difference() {
     CaseShell(PCBLayer1Thick);
     PCBEnvelope();
     }
    
    }
    
    module PCBLayer2() {
    
    difference() {
     CaseShell(PCBLayer2Thick);
     translate([0,0,-(WiringThick + PCBThick/2)])
     PCBEnvelope();
     }
    
    }
    
    module Aluminum() {
     translate([0,0,PlateThick/2])
     cube([1.1*CaseOALength,1.1*CaseOAWidth,PlateThick - Protrusion],center=true);
    }
    
    //-------------------
    // Build things...
    
    ShowPegGrid();
    
    if ("Battery" == Layout)
     Battery();
    
    if ("CaseShell" == Layout)
     CaseShell(CaseOAHeight);
    
    if ("BatteryLayer" == Layout)
     BatteryLayer();
    
    if ("PCBEnvelope" == Layout)
     PCBEnvelope();
    
    if ("PCBLayer1" == Layout)
     PCBLayer1();
    
    if ("PCBLayer2" == Layout)
     PCBLayer2();
    
    if ("Fit" == Layout) {
     BatteryLayer();
     translate([0,0,BatteryHeight + PlateThick])
     color("Green") PCBLayer1();
     translate([0,0,BatteryHeight + PlateThick + PCBLayer1Thick])
     color("Cyan") PCBLayer2();
    }
    
    if ("Show" == Layout) {
     BatteryLayer();
     translate([0,0,BatteryHeight + PlateThick + ShowGap])
     color("Green") PCBLayer1();
     translate([0,0,BatteryHeight + PlateThick + PCBLayer1Thick + 2*ShowGap])
     color("Cyan") PCBLayer2();
    }
    
    if ("Build1" == Layout)
     rotate(90) BatteryLayer();
    
    if ("Build2" == Layout)
     rotate(90) PCBLayer1();
    
    if ("Build3" == Layout)
     translate([0,0,PCBLayer2Thick])
     rotate([0,180,90])
     PCBLayer2();
    
  • Wouxun KG-UV3D Plug Plate

    Based on those measurements that suggest spacing the plugs at 11.5 mm on center, I tweaked that parameter in the source code there and printed another one, just like the other one. Actually, I printed four of the fool things this time:

    Wouxun plug plates - 11.5 mm fixture
    Wouxun plug plates – 11.5 mm fixture

    With the plugs in the gluing fixture and the fixture in the vise, a ring of epoxy around the threaded sides holds them in place:

    Wouxun plug plate - wired
    Wouxun plug plate – wired

    A trial fit in the Wouxun KG-UV3D shows that the jacks prefer the 11.2 mm spacing I measured on the Wouxun headset, but they’ll accept plugs on 11.5 mm centers. I don’t know if that’s a real specification difference, a manufacturing tolerance, or what.

    FWIW, I’ve been using snippets of that cable forever, because it’s perfect for this application: two unshielded conductors and three more inside a braid, supple as a snake. It’s surplus, of course, with a gorgeous push-lock plug (and the jack!) on one end that must have cost a fortune… and which I’ll never to use for anything. Got two of them, just in case.

    Mushing an epoxy putty turd on the top anchors everything in place and protects the wires:

    Wouxun plug plate - epoxy cap
    Wouxun plug plate – epoxy cap

    In point of fact, the cable insulation isn’t anchored inside the blob and a minor tug could pull it loose. There will be a bit of slack at the case to allow for unlatching it from the radio, but the lashup will spend its entire life inside a snug pouch, so it shouldn’t come to any harm. We shall see.

  • Kenwood / Wouxun Headset Jack Spacing

    Wouxun plug mounting plate - overview
    Wouxun plug mounting plate – overview

    Try as I might, I cannot uncover a definitive answer to this simple question: What’s the center-to-center spacing of the mic and earphone jacks on the side of Kenwood and Wouxun HTs?

    The usual searches produce answers like 11 and 12 mm, both of which are obviously wrong, as can be determined eyeballometrically just by holding a scale against the plugs.

    Based on measurements I made on a Wouxun headset, the yellow plug mounting plate put the plugs on 11.2 mm centers and they fit into the KG-UV3D radio; it’s been working fine ever since.

    However, having just measured a speaker/mic and a headset, both from Kenwood, I come up with 11.5 mm. Frankly, I trust the Kenwood hardware a bit more: the plugs seem more rugged and the overall production values are higher.

    The calculation is simple: measure the pin diameters, then subtract half their sum from the outside distance across the pins. Cross-check by adding half the sum to the inside distance between the pins, which should give the same answer. It helps if the pins are actually round.

    The jacks in the Kenwood and Wouxun radios have enough compliance to accept either a Wouxun or a Kenwood headset plug without complaint. Maybe it doesn’t matter?

    Despite that, I made another gluing fixture with 11.5 mm spacing:

    Plug alignment plate - 11.5 mm spacing
    Plug alignment plate – 11.5 mm spacing

    Those are 0.1 inch grids; it’s a little bitty block of smoke-gray polycarbonate from the scrap heap. The plugs are nominally 3.5 mm (which is not 1/8 inch in this universe) and 2.5 mm, with clearance drills #28 and #39.

    Then I tried poking those 11.2 mm spaced plugs, now firmly epoxied in place in the yellow plate, and guess what: they don’t fit, no how no way. That’s not surprising, because there’s no compliance on either side of the joint and the plugs aren’t on the right centers for the fixture. Makes for a good No-Go gauge, I suppose.

    However, I think I’ll tweak the solid model spacing to 11.5 mm and run off another plug mounting plate for the next radio.

    FWIW, our ICOM IC-Z1A HTs use a sensible 10.0 mm spacing and that old fixture worked fine.

  • HT GPS+Voice: Battery Contacts

    For this version of the contacts (the old version is there) that make the GPS interface look like a standard Wouxun lithium battery, I left a bit more of the slot on the brass screw heads and increased the recess depth to compensate:

    HT-GPS Case - Battery contacts
    HT-GPS Case – Battery contacts

    The nuts all have fancy nickel plating, with washers & ring lugs silver-soldered in place:

    HT-GPS PCB - battery contact parts
    HT-GPS PCB – battery contact parts

    The trial fit looks OK:

    HT-GPS Case - PCB and battery contacts - end view
    HT-GPS Case – PCB and battery contacts – end view

    I even found the cutest little flat 1/4 inch wrench that fits 4-40 nuts, so I can do a better job of crunching the PCB between the nuts. That excess screw length has got to go, too…

  • HT GPS+Voice Circuitry: Bare PCB

    Drilling the PCB went fine, as did the etching & silver plating:

    PCB with edge wrap - front
    PCB with edge wrap – front

    The rear side has a fine ground plane:

    PCB with edge wrap - rear
    PCB with edge wrap – rear

    The small spots scattered over the rear mark vias that stitch the front and back planes together; lacking plated-through holes, I solder nippets of 24 AWG wires to both sides. The wrinkly edge comes from solder on the copper foil binding the entire perimeter.

    While I have no hard evidence that all of the fuss & bother matters, the most recent version of this circuit is the quietest yet: the machine noise from the TinyTrak3+ that plagued the first iteration has pretty much vanished.

    I’ll grant you that the silver plating doesn’t look very silvery in these pix, but it’s quite different from the bare copper in person. Here’s the front just after rubbing it in with a vigorous circular motion:

    HT-GPS PCB - raw plated - top
    HT-GPS PCB – raw plated – top
  • HT GPS+Voice Case: Latch Bar

    This iteration of the case latch has slightly larger brass tubing on the ends, hand filed to match the case angle:

    Shaping case latch bar
    Shaping case latch bar

    It’s pretty much the same process described there and is why I set up that slitting saw arbor for the next time.

    The final result looks pretty good:

    HT-GPS Case - Latch plate detail
    HT-GPS Case – Latch plate detail

    Those tubing snippets really must be two different lengths: the bar slides to the right (in that picture) to release the case, so:

    • The short tube and the notch must fit into the space between the edge of the case and the release slot.
    • The long tube slides outward, with a mark to indicate when the notches align with the release slots.

    In principle, you could slide the bar until the shorter tube jams against the latch ramp on the radio, but this case (plus the end caps) turned out to be exactly as long as the distance available and is a rather snug press fit. The next version will be 0.75 mm shorter and should fit better, although snug is good in this situation.

  • Specialty Duct Tape

    Saw this at the local Jo-Anne Fabric and got it on sale:

    Penguin Duck Tape - detail
    Penguin Duck Tape – detail

    Kinda classes up the joint, doesn’t it?

    Penguin Duck Tape - ready for action
    Penguin Duck Tape – ready for action

    Yes, it’s really Duck Tape …