Having twice failed to make music-wire springs work, I rummaged around in the Big Box o’ Small Springs with more diligence and unearthed a pair of coil compression springs that exactly match the pin ferrule OD. Twiddling the solid model produced this longer & flatter version with in-line springs and cylindrical plugs holding them in place:

A closeup of the pin arrangement, which now looks very clean and easy to build:

The OpenSCAD code will print out a quartet of plugs (pick the best two), but having thought of that too late, I turned a pair from a random acrylic rod:

I did remember to solder the wires before assembling the pins this time…

Because the pins now index on their shoulder with the springs at partial extension, I set the drills into the pin vice vise [Update: One can probably be arrested for pin vice] to produce depths displayed by the OpenSCAD program before reaming out the printed holes:
ECHO: "Depth to taper end: 24.72" ECHO: " ferrule end: 15.62" ECHO: " plug end: 4.62"
Then glue the pin plugs into the holder and the flat lid atop the case to capture the battery, clamping everything to the corner of the Sherline’s countertop:

And it Just Worked: nice travel between the limits, smooth operation, it’s the way I should have done it from the beginning*. You knew that all along, right?
Here are the three NB-5L Battery Holder versions, all snuggled up together. The longer and flatter coil-spring version sits on the right:

Now I can take some data…
The OpenSCAD source code:
// Holder for Canon NB-5L Li-Ion battery
// Ed Nisley KE4ZNU August 2011
include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
include </home/ed/Thing-O-Matic/lib/MCAD/boxes.scad>
include </home/ed/Thing-O-Matic/Useful Sizes.scad>
// Layout options
Layout = "Build"; // Case Lid Plugs Show Build Fit
//- Extrusion parameters - must match reality!
// Print with +2 shells and 3 solid layers
ThreadThick = 0.33;
ThreadWidth = 2.0 * ThreadThick;
HoleWindage = 0.2;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
Protrusion = 0.1; // make holes end cleanly
BuildOffset = 3.0; // clearance for build layout
//- Battery dimensions - rationalized from several samples
// Coordinate origin at battery corner by contact plates on bottom surface
BatteryLength = 45.25;
BatteryWidth = 32.17;
BatteryThick = 7.85;
ContactWidth = 2.10;
ContactLength = 4.10;
ContactRecess = 0.85;
ContactOC = 3.18; // center-to-center across contact face
ContactOffset = 4.45; // offset from battery edge
ContactHeight = 3.05; // offset from battery bottom plane
AlignThick = 2.2; // alignment recesses on contact face
AlignDepth = 2.0; // into face
AlignWidth1 = 0.7; // across face at contacts
AlignWidth2 = 2.8; // ... other edge
//- Pin dimensions
PinTipDia = 1.6;
PinTipLength = 10.0;
PinTaperLength = 2.3;
PinShaftDia = 2.4;
PinShaftLength = 6.8;
PinFerruleDia = 3.1;
PinFerruleLength = 2.0;
PinLength = PinTipLength + PinTaperLength + PinShaftLength + PinFerruleLength;
ExtendRelax = 1.5 + ContactRecess; // pin extension when no battery is present
ExtendOvertravel = 1.0; // ... beyond engaged position
//- Spring dimensions
SpringDia = 3.1; // coil OD
SpringMax = 9.3;
SpringLength = SpringMax - 0.3; // slightly compressed
SpringMin = 4.5;
SpringPlugDia = 5.0; // plug retaining the spring
SpringPlugLength = IntegerMultiple(4.0,ThreadWidth);
SpringPlugSides = 12;
SpringTravel = ExtendRelax + ExtendOvertravel;
//- Holder dimensions
GuideRadius = ThreadWidth; // friction fit ridges
GuideOffset = 10;
WallThick = 4*ThreadWidth; // holder sidewalls
BaseThick = 6*ThreadThick; // bottom of holder to bottom of battery
TopThick = 4*ThreadThick; // top of battery to top of holder
ThumbRadius = 10.0; // thumb opening at end of battery
CornerRadius = 3*ThreadThick; // nice corner rounding
CaseLength = SpringPlugLength + SpringLength + PinLength - ExtendRelax
+ BatteryLength + GuideRadius + WallThick;
CaseWidth = 2*WallThick + 2*GuideRadius + BatteryWidth;
CaseThick = BaseThick + BatteryThick + TopThick;
//- XY origin at front left battery corner, Z on platform below that
CaseLengthOffset = -(SpringPlugLength + SpringLength + PinLength - ExtendRelax);
CaseWidthOffset = -(WallThick + GuideRadius);
CaseThickOffset = BaseThick;
LidLength = ExtendRelax - CaseLengthOffset;
echo(str("Depth to taper end: ",
(SpringPlugLength + SpringLength + PinFerruleLength + PinShaftLength + PinTaperLength)));
echo(str(" ferrule end: ",
(SpringPlugLength + SpringLength + PinFerruleLength)));
echo(str(" plug end: ",SpringPlugLength));
//----------------------
// 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);
}
//-------------------
//-- Guides for tighter friction fit
module Guides() {
translate([GuideOffset,-GuideRadius,CaseThickOffset])
PolyCyl(2*GuideRadius,(BatteryThick - Protrusion),4);
translate([GuideOffset,(BatteryWidth + GuideRadius),CaseThickOffset])
PolyCyl(2*GuideRadius,(BatteryThick - Protrusion),4);
translate([(BatteryLength - GuideOffset),-GuideRadius,CaseThickOffset])
PolyCyl(2*GuideRadius,(BatteryThick - Protrusion),4);
translate([(BatteryLength - GuideOffset),(BatteryWidth + GuideRadius),CaseThickOffset])
PolyCyl(2*GuideRadius,(BatteryThick - Protrusion),4);
translate([(BatteryLength + GuideRadius),GuideOffset/2,CaseThickOffset])
PolyCyl(2*GuideRadius,(BatteryThick - Protrusion),4);
translate([(BatteryLength + GuideRadius),(BatteryWidth - GuideOffset/2),CaseThickOffset])
PolyCyl(2*GuideRadius,(BatteryThick - Protrusion),4);
}
//-- Contact pins (holes therefore)
module PinShape() {
union() {
cylinder(r=(PinTipDia + HoleWindage)/2,h=(PinTipLength + Protrusion),$fn=6);
translate([0,0,PinTipLength])
cylinder(r=(PinShaftDia + HoleWindage)/2,
h=(PinTaperLength + PinShaftLength + Protrusion),$fn=6);
translate([0,0,(PinLength - PinFerruleLength)])
cylinder(r=(PinFerruleDia + HoleWindage)/2,
h=(PinFerruleLength + Protrusion),$fn=6);
translate([0,0,(PinLength)])
cylinder(r=(SpringDia + HoleWindage)/2,
h=(SpringLength + Protrusion),$fn=6);
translate([0,0,(PinLength + SpringLength)])
cylinder(r=(SpringPlugDia + HoleWindage)/2,h=(SpringPlugLength + Protrusion),$fn=SpringPlugSides);
translate([0,0,(PinLength + SpringLength + SpringPlugLength)])
cylinder(r=(SpringPlugDia + HoleWindage)/2,h=2*SpringPlugLength,$fn=SpringPlugSides); // extend hole
}
}
module PinAssembly() {
translate([ExtendRelax,ContactOffset,CaseThickOffset + ContactHeight]) {
rotate([0,270,0]) {
PinShape(); // pins
translate([0,(2*ContactOC),0])
PinShape();
}
}
}
//-- Case with origin at battery corner
module Case() {
difference() {
union() {
difference() {
translate([(CaseLength/2 + CaseLengthOffset),
(CaseWidth/2 + CaseWidthOffset),
(CaseThick/2)])
roundedBox([CaseLength,CaseWidth,CaseThick],CornerRadius); // basic case shape
translate([-ExtendOvertravel,-GuideRadius,CaseThickOffset])
cube([(BatteryLength + GuideRadius + ExtendOvertravel),
(BatteryWidth + 2* GuideRadius),
(BatteryThick + Protrusion)]); // battery space
}
Guides();
translate([-ExtendOvertravel,-GuideRadius,BaseThick])
cube([(AlignDepth + ExtendOvertravel),
(AlignWidth1 + GuideRadius),
AlignThick]); // alignment blocks
translate([-ExtendOvertravel,
(BatteryWidth - AlignWidth2),
BaseThick])
cube([(AlignDepth + ExtendOvertravel),
(AlignWidth2 + GuideRadius),
AlignThick]);
}
translate([(-ExtendOvertravel),
(CaseWidthOffset - Protrusion),
(CaseThickOffset + BatteryThick)])
cube([CaseLength,
(CaseWidth + 2*Protrusion),
(TopThick + Protrusion)]); // battery access
translate([(CaseLengthOffset - Protrusion),
(CaseWidthOffset - Protrusion),
(CaseThickOffset + BatteryThick)])
cube([(CaseLength + 2*Protrusion),
(CaseWidth + 2*Protrusion),
(TopThick + Protrusion)]); // battery insertion allowance
translate([(BatteryLength - Protrusion),
(CaseWidth/2 + CaseWidthOffset),
(CaseThickOffset + ThumbRadius)])
rotate([90,0,0])
rotate([0,90,0])
cylinder(r=ThumbRadius,
h=(WallThick + GuideRadius + 2*Protrusion),
$fn=22); // remove thumb notch
PinAssembly();
}
}
module Lid() {
difference() {
translate([0,0,(CaseThick/2 - BaseThick - BatteryThick)])
roundedBox([LidLength,
CaseWidth,CaseThick],CornerRadius);
translate([0,0,-(CaseThick/2)])
cube([(LidLength + 2*Protrusion),
(CaseWidth + 2*Protrusion),
(CaseThick)],center=true);
}
}
module PlugShape() {
difference() {
cylinder(r=SpringPlugDia/2,h=SpringPlugLength,$fn=SpringPlugSides);
translate([0,0,-Protrusion])
PolyCyl(PinShaftDia,(SpringPlugLength + 2*Protrusion),SpringPlugSides/2);
}
}
module Plugs() {
translate([0,ContactOC,0])
PlugShape();
translate([0,-ContactOC,0])
PlugShape();
}
//-------------------
// Build it!
ShowPegGrid();
if (Layout == "Case")
Case();
if (Layout == "Lid")
Lid();
if (Layout == "Plugs")
Plugs();
if (Layout == "Show") { // reveal pin assembly
difference() {
Case();
translate([(CaseLengthOffset - Protrusion),
(CaseWidthOffset - Protrusion + WallThick + ContactOffset + ContactOC),
(BaseThick + ContactHeight)])
cube([(-CaseLengthOffset + Protrusion),
(CaseWidth + 2*Protrusion),
CaseThick + BaseThick - ContactHeight + Protrusion]);
translate([(CaseLengthOffset - Protrusion),
(CaseWidthOffset - Protrusion),
-Protrusion])
cube([(-CaseLengthOffset + Protrusion),
(WallThick + GuideRadius + ContactOffset + Protrusion),
CaseThick]);
}
translate([ExtendRelax,ContactOffset,(CaseThickOffset + ContactHeight)]) { // pins
rotate([0,270,0]) {
%PinShape();
// translate([0,(2*ContactOC),0])
// %PinShape();
}
}
translate([CaseLengthOffset,ContactOffset,(CaseThickOffset + ContactHeight)])
rotate([0,90,0])
PlugShape();
}
if (Layout == "Build") {
translate([-(CaseLength/2 + CaseLengthOffset),-(CaseWidthOffset - BuildOffset),0])
Case();
translate([0,(CaseLengthOffset/2 - BuildOffset),0])
rotate([0,0,90])
Lid();
translate([CaseLengthOffset - SpringPlugDia,-CaseWidth/2,0])
Plugs();
translate([(CaseLengthOffset + SpringPlugDia),-CaseWidth/2,0]) // extra set of plugs
Plugs();
}
if (Layout == "Fit") {
Case();
translate([(-LidLength/2 + ExtendRelax),
(CaseWidth/2 + CaseWidthOffset),
(BaseThick + BatteryThick)])
Lid();
translate([ExtendRelax,ContactOffset,CaseThickOffset + ContactHeight]) { // pins
rotate([0,270,0]) {
%PinShape();
translate([0,(2*ContactOC),0])
%PinShape();
}
}
translate([CaseLengthOffset,
(ContactOffset + ContactOC),
(CaseThickOffset + ContactHeight)])
rotate([0,90,0])
Plugs();
}
(*) Modulo, of course, simply buying a $5 charger from eBay and gutting it. What’s the fun in that?
Comments
8 responses to “NB-5L Holder: Coil Springs”
Hmm, I wonder what the contact resistance is? Now that it’s too late, if you would have added an extra contact (those are BNC center pins, right?) you could have measured the resistance….
– Steven Ciciora
Pretty close to zero, at least after I got enough force from the springs: heavy gold plating on the pins and whatever gold-colored substance they use on those crap batteries (probably brass). The holder has better material and applies more contact force than those tidy steel springs in the Canon charger, anyway.
The shaky trace for that first battery came from essentially zero contact pressure on bent copper wire contacts.
Nope, they’re huge pins from some weird Mil-spec connector, over 3/4 inch long after I cut off the insulation crimp tab. The butt end is nearly 1/8 inch in diameter and the tip of the pin about 1/16 inch!
At today’s prices, the guys at the local “We Buy Gold!” stores would exhibit involuntary hip motions…
Why not use a few of these:
http://www.idinet.com/Test-Probes.aspx/
$2.60 each @ 10
http://www.newark.com/everett-charles-tech/p2662bg-1r1s/test-spring-probe-pcb/dp/50F5572
(of course it is too late for this design ;) )
At this stage, I just wander into the Basement Laboratory Warehouse and figure if I add two of these to one of those, then mount them in that, I can build whatever I need… for free!
Maybe it’s not good product development with commercially available parts. On the other paw, I’m not developing a product. And on the gripping hand, anybody who wants to build one can just buy a handful of those pogo pins and have at it. [grin]
Or, sigh, drop four or five bucks to get a complete charger from halfway around the planet and cannibalize that.
“At today’s prices, the guys at the local “We Buy Gold!” stores would exhibit involuntary hip motions…”
Funny…
The local scrap metal recycler I frequent (usually to buy scrap, not sell) pays just over $1/pound for things like computer mother boards that have _some_ gold connectors showing. While it is counter-productive on many levels, I can’t help myself spending time taking off heavy, non-gold parts like transformers, just to get paid less. But at least I’m not paying $10 to have it recycled.
– Steve
A few weeks ago, the local recycler paid $0.50/pound for aluminum scrap. If you don’t spend a few minutes removing all the steel bits, though, you get $0.10/pound. Copper drops dramatically for junk like “insulated wire” rather than bulk metal.
Can’t imagine what would happen if I walked in with a box of unused heavy-gold-plated connectors… probably have to leave fingerprints.
[…] the sizes are pretty close, so I conjured up another 3D printed battery test fixture for the rundown […]
[…] were a surplus find, with one pin clipped nearly flush to the insulator. I soldered a pair of the same male pins as in the battery holders, with the matching female pins as a crude connector. The unshrunk heatstink tubing isn’t […]