Adapting the NP-BX1 battery holder to use SMT pogo pins worked well:

The next step is to add sockets for those 14 AWG wires:

Start by reaming / hand-drilling all the holes to their nominal size and cleaning out the pogo pin pocket.
Solder wires to the pogo pins and thread them through the holder and lid:

That’s nice, floppy silicone-insulated 24 AWG wire, which may be a bit too thick for this purpose.
The pogo pins will, ideally, seat with the end of the body flush at the holder wall. Make it so:

Dress the wires neatly into their pocket:

Butter the bottom of the lid with epoxy, clamp in place, set it up for curing, then fill the recess:

While it’s curing, make a soldering fixture for the 14 AWG wires:

The holes are on 5 mm centers, in the expectation other battery holders will need different spacing.
Solder it up and stick the wires into the base:

Jam a battery in and It Just Works™:

The traces:
- Green = supply current at 20 mA/div
- Yellow = LED driver transistor base voltage
- Purple = other transistor collector voltage
- White = base – collector voltage = capacitor voltage
The measurement setup was a bit of a hairball:

For completeness, here’s the schematic-and-layout diagram behind the circuitry:

I love it when a plan comes together!
The OpenSCAD source code as a GitHub Gist:
// Holder for Sony NP-BX1 Li-Ion battery | |
// Ed Nisley KE4ZNU January 2013 | |
// 2018-11-15 Adapted for wire leads from 1.5 mm test pins, added upright wire bases | |
// Layout options | |
Layout = "Fit"; // Show Build Fit Case Lid Pins | |
//- Extrusion parameters - must match reality! | |
// Print with +2 shells and 3 solid layers | |
ThreadThick = 0.25; | |
ThreadWidth = 0.35; | |
HoleWindage = 0.2; | |
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); | |
Protrusion = 0.1; // make holes end cleanly | |
inch = 25.4; | |
BuildOffset = 3.0; // clearance for build layout | |
Gap = 2.0; // separation for Fit parts | |
//- Basic dimensions | |
WallThick = 4*ThreadWidth; // holder sidewalls | |
BaseThick = 6*ThreadThick; // bottom of holder to bottom of battery | |
TopThick = 6*ThreadThick; // top of battery to top of holder | |
//- Battery dimensions - rationalized from several samples | |
// Coordinate origin at battery contact face with key openings below contacts | |
Battery = [43.0,30.0,9.5]; // X = length, Y = width, Z = thickness | |
Contacts = [[-0.75,6.0,6.2],[-0.75,16.0,6.2]]; // relative to battery edge, front, and bottom | |
ContactOC = Contacts[1].y - Contacts[0].y; | |
ContactCenter = Contacts[0].y + ContactOC/2; | |
KeyBlocks = [[1.75,3.70,2.90],[1.75,3.60,2.90]]; // recesses in battery face set X position | |
//- Pin dimensions | |
ID = 0; | |
OD = 1; | |
LENGTH = 2; | |
PinShank = [1.5,2.0,6.5]; // shank, flange, compressed length | |
PinFlange = [1.5,2.0,0.5]; // flange, length included in PinShank | |
PinTip = [0.9,0.9,2.5]; // extended spring-loaded tip | |
PinChannel = PinFlange[LENGTH] + 0.5; // cut behind flange for solder overflow | |
PinRecess = 3.0; // recess behind pin flange end for epoxy fill | |
echo(str("Contact tip dia: ",PinTip[OD])); | |
echo(str(" .. shank dia: ",PinShank[ID])); | |
OverTravel = 0.5; // space beyond battery face at X origin | |
//- Holder dimensions | |
GuideRadius = ThreadWidth; // friction fit ridges | |
GuideOffset = 7; // from compartment corners | |
ThumbRadius = 10.0; // thumb opening at end of battery | |
CornerRadius = 3*ThreadThick; // nice corner rounding | |
CaseSize = [Battery.x + PinShank[LENGTH] + OverTravel + PinRecess + GuideRadius + WallThick, | |
Battery.y + 2*WallThick + 2*GuideRadius, | |
Battery.z + BaseThick + TopThick]; | |
CaseOffset = [-(PinShank[LENGTH] + OverTravel + PinRecess),-(WallThick + GuideRadius),0]; // position around battery | |
LidOverhang = 2.0; // over top of battery for retention | |
LidSize = [-CaseOffset.x + LidOverhang,CaseSize.y,TopThick]; | |
LidOffset = [0.0,CaseOffset.y,0]; | |
//- Wire struts | |
StrutDia = 1.6; // AWG 14 = 1.6 mm | |
StrutOC = 45; | |
StrutSides = 3*4; | |
StrutBase = [StrutDia,StrutDia + 4*WallThick,CaseSize.z - TopThick]; // ID = wire, OD=buildable | |
//---------------------- | |
// 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); | |
} | |
//------------------- | |
//-- Guides for tighter friction fit | |
module Guides() { | |
translate([GuideOffset,-GuideRadius,0]) | |
PolyCyl(2*GuideRadius,(Battery.z - Protrusion),4); | |
translate([GuideOffset,(Battery.y + GuideRadius),0]) | |
PolyCyl(2*GuideRadius,(Battery.z - Protrusion),4); | |
translate([(Battery.x - GuideOffset),-GuideRadius,0]) | |
PolyCyl(2*GuideRadius,(Battery.z - Protrusion),4); | |
translate([(Battery.x - GuideOffset),(Battery.y + GuideRadius),0]) | |
PolyCyl(2*GuideRadius,(Battery.z - Protrusion),4); | |
translate([(Battery.x + GuideRadius),GuideOffset/2,0]) | |
PolyCyl(2*GuideRadius,(Battery.z - Protrusion),4); | |
translate([(Battery.x + GuideRadius),(Battery.y - GuideOffset/2),0]) | |
PolyCyl(2*GuideRadius,(Battery.z - Protrusion),4); | |
} | |
//-- Contact pins | |
// Rotated to put them in their natural oriention | |
// Aligned to put tip base / end of shank at Overtravel limit | |
module PinShape() { | |
translate([-(PinShank[LENGTH] + OverTravel),0,0]) | |
rotate([0,90,0]) | |
rotate(180/6) | |
union() { | |
PolyCyl(PinTip[OD],PinShank[LENGTH] + PinTip[LENGTH],6); | |
PolyCyl(PinShank[ID],PinShank[LENGTH] + Protrusion,6); // slight extension for clean cuts | |
PolyCyl(PinFlange[OD],PinFlange[LENGTH],6); | |
} | |
} | |
// Position pins to put end of shank at battery face | |
// Does not include recess access into case | |
module PinAssembly() { | |
union() { | |
for (p = Contacts) | |
translate([0,p.y,p.z]) | |
PinShape(); | |
translate([-(PinShank[LENGTH] + OverTravel) + PinChannel/2, // solder space | |
ContactCenter, | |
Contacts[0].z]) | |
cube([PinChannel,(Contacts[1].y - Contacts[0].y),PinFlange[OD]],center=true); | |
for (j=[-1,1]) // wire channels | |
translate([-(PinShank[LENGTH] + OverTravel - PinChannel/2), | |
j*ContactOC/4 + ContactCenter, | |
Contacts[0].z - PinFlange[OD]/2]) | |
rotate(180/6) | |
PolyCyl(PinFlange[OD],CaseSize.z,6); | |
} | |
} | |
//-- Case with origin at battery corner | |
module Case() { | |
difference() { | |
union() { | |
difference() { | |
union() { | |
translate([(CaseSize.x/2 + CaseOffset.x), // basic case shape | |
(CaseSize.y/2 + CaseOffset.y), | |
(CaseSize.z/2 - BaseThick)]) | |
hull() | |
for (i=[-1,1], j=[-1,1], k=[-1,1]) | |
translate([i*(CaseSize.x/2 - CornerRadius), | |
j*(CaseSize.y/2 - CornerRadius), | |
k*(CaseSize.z/2 - CornerRadius)]) | |
sphere(r=CornerRadius/cos(180/8),$fn=8); // cos() fixes undersize spheres! | |
hull() // wire strut bases | |
for (j=[-1,1]) | |
translate([0,j*StrutOC/2 + Battery.y/2,-BaseThick]) | |
rotate(180/StrutSides) | |
cylinder(d=StrutBase[OD],h=StrutBase[LENGTH],$fn=StrutSides); | |
translate([0,Battery.y/2,StrutBase[LENGTH]/2 - BaseThick]) | |
cube([2*StrutBase[OD],StrutOC,StrutBase[LENGTH]],center=true); | |
} | |
translate([-OverTravel,-GuideRadius,0]) | |
cube([(Battery.x + GuideRadius + OverTravel), | |
(Battery.y + 2*GuideRadius), | |
(Battery.z + Protrusion)]); // battery space | |
} | |
Guides(); // improve friction fit | |
translate([-OverTravel,-GuideRadius,0]) // battery keying blocks | |
cube(KeyBlocks[0] + [OverTravel,GuideRadius,0],center=false); | |
translate([-OverTravel,(Battery.y - KeyBlocks[1].y),0]) | |
cube(KeyBlocks[1] + [OverTravel,GuideRadius,0],center=false); | |
} | |
translate([2*CaseOffset.x, // battery top access | |
(CaseOffset.y - Protrusion), | |
Battery.z]) | |
cube([2*CaseSize.x,(CaseSize.y + 2*Protrusion),(TopThick + Protrusion)]); | |
if (false) | |
translate([(CaseOffset.x - Protrusion), // battery insertion allowance | |
(CaseOffset.y - Protrusion), | |
Battery.z]) | |
cube([(CaseSize.x + 2*Protrusion),(CaseSize.y + 2*Protrusion),(TopThick + Protrusion)]); | |
for (j=[-1,1]) // strut wires | |
translate([0,j*StrutOC/2 + Battery.y/2,-(BaseThick + Protrusion)]) | |
PolyCyl(StrutBase[ID],StrutBase[LENGTH] + 2*Protrusion,6); | |
for (i=[-1,1], j=[-1,1]) | |
translate([i*StrutBase[OD],j*StrutOC/2 + Battery.y/2,-(BaseThick + Protrusion)]) | |
rotate(180/StrutSides) | |
PolyCyl(StrutBase[OD],StrutBase[LENGTH] + 2*Protrusion,StrutSides); | |
translate([(Battery.x - Protrusion), // remove thumb notch | |
(CaseSize.y/2 + CaseOffset.y), | |
(ThumbRadius)]) | |
rotate([90,0,0]) | |
rotate([0,90,0]) | |
cylinder(r=ThumbRadius, | |
h=(WallThick + GuideRadius + 2*Protrusion), | |
$fn=22); | |
PinAssembly(); | |
translate([CaseOffset.x + PinRecess + Protrusion,(Contacts[1].y + Contacts[0].y)/2,Contacts[0].z]) | |
translate([-PinRecess,0,0]) | |
cube([2*PinRecess, | |
(Contacts[1].y - Contacts[0].y + PinFlange[OD]), | |
2*PinFlange[OD]],center=true); | |
} | |
} | |
// Lid position offset to match case | |
module Lid() { | |
difference() { | |
translate([-LidSize.x/2 + LidOffset.x + LidOverhang,LidSize.y/2 + LidOffset.y,0]) | |
difference() { | |
hull() | |
for (i=[-1,1], j=[-1,1], k=[-1,1]) | |
translate([i*(LidSize.x/2 - CornerRadius), | |
j*(LidSize.y/2 - CornerRadius), | |
k*(LidSize.z - CornerRadius)]) // double thickness for flat bottom | |
sphere(r=CornerRadius,$fn=8); | |
translate([0,0,-LidSize.z/2]) // remove bottom | |
cube([(LidSize.x + 2*Protrusion),(LidSize.y + 2*Protrusion),LidSize.z],center=true); | |
translate([LidSize.x/8,0,0]) | |
cube([LidSize.x/4,0.75*LidSize.y,4*ThreadThick],center=true); // epoxy recess | |
} | |
translate([0,0,-(Contacts[0].z + PinFlange[OD])]) // punch wire holes | |
PinAssembly(); | |
} | |
} | |
//------------------- | |
// Build it! | |
if (Layout == "Case") | |
Case(); | |
if (Layout == "Lid") | |
Lid(); | |
if (Layout == "Pins") { | |
color("Silver",0.5) | |
PinShape(); | |
PinAssembly(); | |
} | |
if (Layout == "Show") { // reveal pin assembly | |
difference() { | |
Case(); | |
translate([(CaseOffset.x - Protrusion), | |
Contacts[1].y, | |
Contacts[1].z]) | |
cube([(-CaseOffset.x + Protrusion), | |
CaseSize.y, | |
(CaseSize.z - Contacts[0].z + Protrusion)]); | |
translate([(CaseOffset.x - Protrusion), | |
(CaseOffset.y - Protrusion), | |
0]) | |
cube([(-CaseOffset.x + Protrusion), | |
Contacts[0].y + Protrusion - CaseOffset.y, | |
CaseSize.z]); | |
} | |
translate([0,0,Battery.z + Gap]) | |
Lid(); | |
color("Silver",0.15) | |
PinAssembly(); | |
} | |
if (Layout == "Build") { | |
translate([-(CaseSize.x/2 + CaseOffset.x),-(CaseOffset.y - BuildOffset),BaseThick]) | |
Case(); | |
translate([CaseSize.x/2,-LidSize.x/2,0]) | |
rotate(90) | |
Lid(); | |
} | |
if (Layout == "Fit") { | |
Case(); | |
translate([0,0,(Battery.z + Gap)]) | |
Lid(); | |
color("Silver",0.25) | |
PinAssembly(); | |
} | |
Very nice. Those projecting bus bars make me wonder if they make a miniature sized cap that they put on the ends of rebars at construction sites to prevent workers from becoming impaled on them. I wouldn’t want OSHA coming in and shutting down the basement laboratory :)
They do call for a bit of dressing up, don’t they? A printed cap seems way too bulky; perhaps something from the brass tube snippet collection is in order.
Ah! Obviously, the Tiny Lathe™ needs a Tiny Ball Turner™!