Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
Of late, something in the pile of input devices attached to my main PC has been feeding occasional bursts of upward scroll commands, to the extent that editing long documents (something I do quite a bit of, oddly enough) was becoming difficult. By process of elimination, the culprit turned out to be the Kensington trackball to the left of the keyboard: unplugging it eliminated the problem.
Having had problems with that thing before and having gotten considerable feedback from other folks, I had a general idea of how to proceed: putz with the IR emitter-detector pair, but not very much. A side view of the pair with the trackball cup and scroll ring removed:
Scroll ring IR emitter-detector quadrature pair
Now, what’s weird about that setup is that the detector lens seems to be pointing in the wrong direction: away from the emitter’s lens. You know it’s the detector because it’s tinted: there’s no point in filtering the emitter’s output (although I have seen gray-tinted IR LEDs, which I think is just to mark them as different from visible LEDs). Here’s proof: a pure IR picture from my Sony DSC-F717 in Nightshot (a.k.a. IR) mode through a Hoya R72 visible-block filter:
Quadrature pair in pure IR
Some possibilities for why the detector is backwards:
It’s an assembly screwup (unlikely, but possible)
That’s not a lens, it’s a locating tab (different on emitter & detector?)
The backside uses the metal conductors as slits to enhance the signal (my favorite)
Here’s a grossly image-enhanced blowup of the detector from that picture:
Quadrature IR detector in pure IR – detail
The case becomes transparent in pure IR, so you can see the metal lead frame inside. I think they’re using the gaps between the leads to enhance the contrast of the scroll ring edges passing through the beam: absolutely no IR except when a gap aligns with a scroll ring opening.
[Update: read the comments for a different interpretation; I’m probably wrong.]
That would also explain why the pair seems so sensitive to alignment: there’s very little IR hitting the detector, because the IR illumination passes through the transparent-to-IR case and vanishes out the far side, with only a tiny bit reflected to the sensor!
Anyhow, I pushed the pair minutely toward each other, just enough to feel the leads bend, and put everything back together. So far it seems to be working perfectly, but it’s done that before …
[Comment: Jack found a different solution that might produce better results:
Just got the Problem with my Scroll ring and thanks to your blog i digged a bit deeper.
here is the Solution for my Problem:
I checked this while connected and i found that bending worked only for a short time, so i gave a closer look to the contacts.
all are soldered from below BUT two contacts are on the upper side. normaly solder should flow into but here it was as simple as just resolder the receiver with enough solder an its now working again. (btw a realigned the magnet to get a better response)
Thanks Jack
ps. the size of the cuts in the metall from the scroll ring differ, a shame for that price..
It’s certainly worth trying, particularly when your Expert Mouse trackball isn’t working…
Having twicefailed 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:
NB-5L Holder – Coil spring – solid model
A closeup of the pin arrangement, which now looks very clean and easy to build:
NB-5L Holder – Coil spring – detail
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:
Turning spring plugs
I did remember to solder the wires before assembling the pins this time…
Pin assemblies
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:
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:
Gluing pin assemblies
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:
After that failure, I thought maybe making the spring guide pocket a bit wider and seating the spring wire in a solid plug would work. A tweak to the OpenSCAD script produced this, along with slightly larger locating ribs around the battery compartment:
NB-5L Holder – Plug spring – solid model
A closer look at the plug spring assembly:
NB-5L Holder – Plug spring – detail
The hole is now slightly larger, distinct from the side of the pocket, and the partition between the pocket and plug (although something of a formality) seats the plug during assembly. The plug started out at 3 mm in diameter, as I intended to try ramming a heated wire into a length of filament. That worked, mmmm, somewhat poorly, so I drilled a hole in a length of filament:
Music wire in filament plug
Unfortunately, that whole bodge didn’t work any better than the spring in the first pass at a holder, so I gave up and cast the springs in epoxy. The OpenSCAD code produces a 5 mm diameter hole that should provide a larger epoxy plate with better grip than the 3 mm holes in this picture, but it probably won’t make much difference:
Music wire in epoxy plug
The alert reader will note a complete faceplant: yeah, I forgot to solder the wires into the pins before blobbing the springs in place. Fortunately, the epoxy cures slowly enough that I could:
Take the picture
Immediately see the obvious problem
Ease the music wire springs out just a tidge
Extract the pins
Quick-like-a-bunny solder wires to pins
Insert pins with proper polarity
Ease springs back in place
I hate it when that happens…
With springs & wires properly in place and the epoxy cured overnight, the pins had considerably better springiness and free motion than before, although they didn’t have quite the range of travel I wanted. I think the spring wire bent slightly on the first push, as the pins never came quite as far out after that.
So this was a qualified success, but not a solid win. Time for round three…
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 = "Show"; // Case Lid 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.0;
PinFerruleLength = 2.0;
PinLength = PinTipLength + PinTaperLength + PinShaftLength + PinFerruleLength;
PinHoleOffset = 13.9; // tip to spring hole
ExtendRelax = 1.5 + ContactRecess; // pin extension when no battery is present
ExtendOvertravel = 1.0; // ... beyond engaged position
//- Holder dimensions
GuideRadius = ThreadWidth; // friction fit ridges
GuideOffset = 10;
WallThick = 4*ThreadWidth; // holder sidewalls
BaseThick = IntegerMultiple(6.0,ThreadThick); // bottom of holder to bottom of battery
TopThick = 6*ThreadThick; // top of battery to top of holder
ThumbRadius = 10.0; // thumb opening at end of battery
CornerRadius = 3*ThreadThick; // nice corner rounding
CaseLength = 2*WallThick + PinLength - ExtendRelax + ExtendOvertravel + BatteryLength + GuideRadius;
CaseWidth = 2*WallThick + 2*GuideRadius + BatteryWidth;
CaseThick = BaseThick + BatteryThick + TopThick;
//- XY origin at front left battery corner, Z on platform below that
CaseLengthOffset = -(WallThick + PinLength - ExtendRelax + ExtendOvertravel);
CaseWidthOffset = -(WallThick + GuideRadius);
CaseThickOffset = BaseThick;
LidLength = ExtendRelax - CaseLengthOffset;
//- Spring dimensions
SpringPlugDia = 5.0; // epoxy plug holding spring wire
SpringPlugLength = IntegerMultiple(1.5,ThreadThick);
SpringDia = 0.024 * inch; // music wire spring
SpringTravel = ExtendRelax + ExtendOvertravel;
SpringLength = BaseThick + ContactHeight - SpringPlugLength - 2*ThreadThick;
echo(str("Spring wire from end: ",WallThick + PinLength - PinHoleOffset));
echo(str(" from side: ",WallThick + GuideRadius + ContactOffset));
echo(str("Pin spacing on centers: ",ContactOC));
//----------------------
// 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() {
PolyPin = false;
union() {
if (PolyPin)
PolyCyl(PinTipDia,(PinTipLength + Protrusion));
else
cylinder(r=(PinTipDia + HoleWindage)/2,h=(PinTipLength + Protrusion),$fn=6);
translate([0,0,PinTipLength])
if (PolyPin)
PolyCyl(PinShaftDia,(PinTaperLength + PinShaftLength + Protrusion));
else
cylinder(r=(PinShaftDia + HoleWindage)/2,
h=(PinTaperLength + PinShaftLength + Protrusion),$fn=6);
translate([0,0,(PinLength - PinFerruleLength)])
if (PolyPin)
PolyCyl(PinFerruleDia,(PinFerruleLength + Protrusion));
else
cylinder(r=(PinFerruleDia + HoleWindage)/2,
h=(PinFerruleLength + Protrusion),$fn=6);
translate([0,0,PinLength])
if (PolyPin)
PolyCyl(PinFerruleDia,PinLength); // very long holes to punch case
else
cylinder(r=(PinFerruleDia + HoleWindage)/2,h=PinLength,$fn=6);
}
}
module PinAssembly() {
translate([ExtendRelax,ContactOffset,CaseThickOffset + ContactHeight]) {
rotate([0,270,0]) {
PinShape(); // pins
translate([0,(2*ContactOC),0])
PinShape();
}
}
translate([-(PinHoleOffset - ExtendRelax + SpringTravel/2 - SpringDia/2 - HoleWindage/2),
ContactOffset,
(CaseThickOffset + ContactHeight - SpringLength/2 - Protrusion)]) {
cube([(SpringTravel + SpringDia/2 + HoleWindage),
PinShaftDia,
(SpringLength + 2*Protrusion)],
center=true); // spring deflection pocket
translate([0,(2*ContactOC),0])
cube([(SpringTravel + SpringDia/2 + HoleWindage),
PinShaftDia,
(SpringLength + 2*Protrusion)],
center=true);
}
translate([-(PinHoleOffset - ExtendRelax),
ContactOffset,
(-Protrusion/2)]) {
PolyCyl(SpringDia,(BaseThick + ContactHeight + Protrusion),4); // spring wire
PolyCyl(SpringPlugDia,(SpringPlugLength + Protrusion)); // wire holder
translate([0,(2*ContactOC),0]) {
PolyCyl(SpringDia,(BaseThick + ContactHeight + Protrusion),4);
PolyCyl(SpringPlugDia,(SpringPlugLength + Protrusion));
}
}
}
//-- 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);
}
}
//-------------------
// Build it!
ShowPegGrid();
if (Layout == "Case")
Case();
if (Layout == "Lid")
Lid();
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();
}
}
}
if (Layout == "Build") {
translate([-(CaseLength/2 + CaseLengthOffset),-(CaseWidthOffset - BuildOffset),0])
Case();
translate([0,(CaseLengthOffset/2 - BuildOffset),0])
rotate([0,0,90])
Lid();
}
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();
}
}
}
The first version of the NB-5L battery holder worked well enough to get some initial performance curves from the assortment of eBay batteries. I bought one apiece from four different vendors for around $3 each; an order of magnitude less than OEM Canon NB-5L camera batteries. Based on past experience, I didn’t expect much and, lo-and-behold, I wasn’t disappointed in the least! Clicky for more dots:
Canon NB-5L – first tests
Using a 500 mA discharge current (roughly C/2) seemed reasonable, but I have no idea what the camera actually draws and the Canon manual isn’t forthcoming. These are all hot off the Canon charger.
That nice long curve on the top is the OEM Canon NB-5L that came with the camera and delivers pretty much its rated 1050 mAh.
The generic batteries have two faults:
Low discharge voltage (high internal resistance?)
Much less than their claimed capacity (they lie!)
The one labeled D Group was advertised as 1500 mAh, which seemed unreasonable on the face of it. The battery case says 1050 mAh and the vendor said their manufacturer “must have shipped them the wrong batteries”. Yeah, right, like they hadn’t noticed up. They wanted me to return it (on their dime, by “refusing” the shipment, which is, AFAICT, prohibited after you open the package), which says that they didn’t have any batteries with “1500 mAh” printed on the side for an exchange. Of course, their advertising for the other NB-5L batteries they offer on eBay hasn’t changed, so … they lie!
The Anonymous Gray battery is particularly feeble; I may harvest the frame and connector and battery protection circuit to build an external battery pack with far more capacity.
The crinkly black trace comes from testing that battery with wires taped in place before I got the first version of the holder up & running well enough to take the rest of the measurements.
Only one generic battery has a manufacturer’s name, two lack regulatory agency markings (not that I expect any to comply with the requirements implied by those markings), and all four are obviously junk. I’ll use them for around-the-house pix with the charger close at hand, but … now we all know that you don’t get something for nothing. No surprise there, eh?
The first pass at a holder for a Canon NB-5L battery didn’t quite work, but the failure was instructive. The overall layout was fine; the battery fit well, it’s just that the pins and springs didn’t function properly.
NB-5L Holder – Internal spring – solid model
I thought a simple straight music wire spring pushed into a hole with a pocket to limit the pin travel would suffice. Watching it build showed that the pocket came out too small and the spring hole was almost completely closed, despite a bit of HoleWindage.
Here’s a closer look at the spring arrangement, with a pocket at the bottom for an epoxy blob after it became obvious the ABS couldn’t properly anchor the pin.
NB-5L Holder – Internal spring – detail
Drilling out the holes to allow free pin movement ended up with #52 for the tip, #40 for the shaft, and #31 for the ferrule at the end; choose for an easy slip fit.
I used 0.024 inch (0.6 mm) music wire, which fit neatly into the pin’s inspection hole. Drilling that (#73 drill) into the nearly closed hole through the bottom showed that things weren’t working well: far too much resistance along what should be a half-open channel.
With the pin in place and a stub of wire pushed upward into the pin, the pins moved very stiffly and tended to not return to their rest position. Minus the spring wire, they slid freely.
After a bit of this and that, I tried 0.020 music wire, which didn’t have enough return force at all.
The end of the spring wire moved around a lot more than I think it should have, gradually turning the hole into an oval. I drilled two pockets in the bottom (and changed the solid model to match what you see above) and cast a dab of epoxy into each hole; that solved the moving-around problem, but the pins were still too stiff.
NB-5L Holder – first version – bottom
The weird orange color comes from a few layers of Safety Orange filament that melded into white in mid-flight. No reason to use fancy filament on a prototype, methinks; that’s what was in place when I started.
But I glued the cap on anyway to see if the pins would work well enough to run some early battery tests. This is what it looked like before gluing the cap:
NB-5L Holder – first version
The Powerpole connectors came from one of those packs, with the wires soldered into the ends of the pins so as to not block the inspection holes that I’m using for the music wire springs.
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 = "Show"; // Case Lid 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.0;
PinFerruleLength = 2.0;
PinLength = PinTipLength + PinTaperLength + PinShaftLength + PinFerruleLength;
PinHoleOffset = 13.9; // tip to spring hole
//- Spring dimensions
ExtendRelax = 1.5 + ContactRecess; // pin extension when no battery is present
ExtendOvertravel = 1.0; // ... beyond engaged position
SpringDia = 0.024 * inch; // music wire spring
SpringTravel = ExtendRelax + ExtendOvertravel;
SpringLength = 4.0 + PinShaftDia/2; // free length below pin centerline
//- Holder dimensions
GuideRadius = ThreadWidth; // friction fit ridges
GuideOffset = 10;
WallThick = 4*ThreadWidth; // holder sidewalls
BaseThick = IntegerMultiple(6.0,ThreadThick); // bottom of holder to bottom of battery
TopThick = 6*ThreadThick; // top of battery to top of holder
ThumbRadius = 10.0; // thumb opening at end of battery
CornerRadius = 3*ThreadThick; // nice corner rounding
CaseLength = 2*WallThick + PinLength - ExtendRelax + ExtendOvertravel + BatteryLength + GuideRadius;
CaseWidth = 2*WallThick + 2*GuideRadius + BatteryWidth;
CaseThick = BaseThick + BatteryThick + TopThick;
//- XY origin at front left battery corner, Z on platform below that
CaseLengthOffset = -(WallThick + PinLength - ExtendRelax + ExtendOvertravel);
CaseWidthOffset = -(WallThick + GuideRadius);
CaseThickOffset = BaseThick;
LidLength = ExtendRelax - CaseLengthOffset;
SpringPlugDia = 3.0; // filament snippet holding spring wire
SpringPlugLength = IntegerMultiple(1.0,ThreadThick);
echo(str("Spring wire from end: ",WallThick + PinLength - PinHoleOffset));
echo(str(" from side: ",WallThick + GuideRadius + ContactOffset));
echo(str("Pin spacing on centers: ",ContactOC));
//----------------------
// 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() {
PolyPin = false;
union() {
if (PolyPin)
PolyCyl(PinTipDia,(PinTipLength + Protrusion));
else
cylinder(r=(PinTipDia + HoleWindage)/2,h=(PinTipLength + Protrusion),$fn=6);
translate([0,0,PinTipLength])
if (PolyPin)
PolyCyl(PinShaftDia,(PinTaperLength + PinShaftLength + Protrusion));
else
cylinder(r=(PinShaftDia + HoleWindage)/2,
h=(PinTaperLength + PinShaftLength + Protrusion),$fn=6);
translate([0,0,(PinLength - PinFerruleLength)])
if (PolyPin)
PolyCyl(PinFerruleDia,(PinFerruleLength + Protrusion));
else
cylinder(r=(PinFerruleDia + HoleWindage)/2,
h=(PinFerruleLength + Protrusion),$fn=6);
translate([0,0,PinLength])
if (PolyPin)
PolyCyl(PinFerruleDia,PinLength); // very long holes to punch case
else
cylinder(r=(PinFerruleDia + HoleWindage)/2,h=PinLength,$fn=6);
}
}
module PinAssembly() {
translate([ExtendRelax,ContactOffset,CaseThickOffset + ContactHeight]) { // pins
rotate([0,270,0]) {
PinShape();
translate([0,(2*ContactOC),0])
PinShape();
}
}
translate([-(PinHoleOffset - ExtendRelax + SpringTravel/2),
ContactOffset,
(CaseThickOffset + ContactHeight - SpringLength/2 + Protrusion/2)]) {
cube([SpringTravel,
(2*SpringDia),
(SpringLength + Protrusion)],
center=true); // spring deflection pocket
translate([0,(2*ContactOC),0])
cube([SpringTravel,
(2*SpringDia),
(SpringLength + Protrusion)],
center=true);
}
translate([-(PinHoleOffset - ExtendRelax),
ContactOffset,
(-Protrusion/2)]) {
PolyCyl(SpringDia,(BaseThick + ContactHeight + Protrusion)); // spring wire
PolyCyl(SpringPlugDia,(SpringPlugLength + Protrusion)); // wire holder
translate([0,(2*ContactOC),0]) {
PolyCyl(SpringDia,(BaseThick + ContactHeight + Protrusion));
PolyCyl(SpringPlugDia,(SpringPlugLength + Protrusion));
}
}
}
//-- 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);
}
}
//-------------------
// Build it!
ShowPegGrid();
if (Layout == "Case")
Case();
if (Layout == "Lid")
Lid();
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();
}
}
}
if (Layout == "Build") {
translate([-(CaseLength/2 + CaseLengthOffset),-(CaseWidthOffset - BuildOffset),0])
Case();
translate([0,(CaseLengthOffset/2 - BuildOffset),0])
rotate([0,0,90])
Lid();
}
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();
}
}
}
Before trotting off to college, my Shop Assistant repaired a pair of headphones she’d scrounged at the end of her Senior year; they were nice Skullcandy on-ear phones with one dead cup. The previous owner evidently wasn’t into fixing things and bequeathed them to her.
She dismantled the offending cup to find some really grody soldering that ought to have produced a cold solder joint: the common lead wasn’t making contact with the plug. Alas, the only way to proceed was to slice the injection-molded cover off the plug and see what was inside; to our surprise, everything looked fine.
We then cut an inch off the cable and pulled the conductors out:
Broken headphone cable conductors
Well, that was easy! Here’s a closer look:
Broken headphone conductor – detail
The three broken wires (only one of which was completely disconnected) failed exactly at the end of that plug covering. It had strain relief notches, but we guessed the previous owner had no qualms about bending the cable hard against the end of the plug.
She soldered it up, shrank some heat stink tubing around the plug and its sliced cover, wrapped self-vulcanizing tape around the junction for better strain relief, and it’s all good. She’ll get plenty of use out of the headphones in the dorm …
A first cut at a holder for Canon NB-5L batteries with those dimensions, with the intent of connecting them to a battery tester.
NB-5L Battery Holder Doodle
The cloud in the middle of the bottom holds pin dimensions, which I measured after I’d been doodling for a bit. They come from my heap; they’re nice heavy-gold plated male pins (yeah, I have the other gender, too) intended for a multi-pin connector. They have a convenient hole that’s normally used to verify you’ve actually soldered the wire properly. I plan to stick a music-wire spring in the hole and secure it through the bottom of the holder with a rectangular pocket below the pin that limits the travel in both directions. Drilling the hole completely through the pin to let the spring wire stick out would prevent having it fall out at the end of travel.
The spring pocket dimensions are right down around the very limit of the feature sizes my TOM can achieve. I’m not sure those blind holes will actually open up far enough.
I’m also not sure the Powerpoles will actually fit in there like that. There’s nothing wrong with pigtail leads.
It’s obviously styled after the Official Canon NB-5L charger, although they use nice bent-steel spring contacts that are trivially easy to make in mass production: