Ed Nisley's Blog: Shop notes, electronics, firmware, machinery, 3D printing, laser cuttery, and curiosities. Contents: 100% human thinking, 0% AI slop.
After I get the next GPS+voice interface running on the (yet-to-be-bought) Wouxun KG-UV3D radio, a pair of reasonably new 1A17KG-3 7.4 V 1.7 A·h lithium battery packs will be floating around with nothing to do; the GPS interface connects an external battery to the radio, so there’s no need for the OEM battery.
Before doing anything else, it’d be useful to know the actual capacity. The pack has flush terminals, so I snipped off two lengths of shield braid, jammed a wire into each one, and taped them in place:
Battery pack – braid contacts
That obviously wasn’t going to last, so I added some closed-cell foam:
Battery pack – foam compression
And then, ever so gently, crunched a clamp around the whole mess:
Battery Pack – clamped contacts
Crude, but workable, although the ragged start to the test showed I was too gentle. Another click of the clamp and everything settled down just fine:
Wouxun Pack
In round numbers, the pack delivers 1.6 A·h down to 7.0 V and then falls off very rapidly to the 6.0 V that ended the test.
A string of three red / amber LEDs adds up to 3×1.9 = 5.7 V. A dumb DC blinky light running from 7.4 V has 77% efficiency, which isn’t all that bad, and 70% at the start. A current-regulating switcher might give 85% to 90% at the cost of considerable circuit complexity and wouldn’t be feasible for four independent blinky channels.
The starting voltage, fresh from the charger, is just shy of 8.5 V, which is why I figured I could get away with 9 V from the external pack through the GPS interface. So far, so good.
Obviously, if those packs are to be useful, I must conjure up a better battery holder. Having already designed a battery-shaped case for the GPS interface, it should be easy enough to build a radio-shaped mount for the pack.
The Y axis on my Sherline CNC mill has developed about 8 mils of backlash, a bit more than seems reasonable. Some poking around shows that the anti-backlash nut is loose while in the middle of the leadscrew and snug while at either end, which suggests the leadscrew thread is also worn. That’s no surprise, as I didn’t figure out that having a bellows over the leadscrew was a Good Thing until, let us say, considerably later than I should.
If I must replace the leadscrew, I may as well take the whole XY assembly apart, clean everything, and replace the consumables. So I ordered a sack o’ parts from Sherline; they’re all cheap and readily available. The overall index has the exploded diagrams and the parts list for my mill boiled down to:
54161 Y axis leadscrew (9 inch)
50140 Y axis anti-backlash nut
50200 Y axis nut
50171 X axis leadscrew
50130 X axis anti-backlash nut
40890 X axis nut
50150 anti-backlash lock
The only gotcha: nowhere (that I can find, anyway) is it written how to get the leadscrew nuts out of the stage. It turns out that the holes through the stage aren’t uniform: the X narrower on the right and the Y on the front, so you must drive the X axis nut out to the left and the Y axis nut out to the rear. The counterbore is visible just behind the anti-backlash nut if you know what to look for, so you’re driving the axis nut away from the backlash nut.
On the X axis:
X axis leadscrew hole counterbore
On the Y axis:
Y axis leadscrew hole counterbore
Trust me on this: you cannot drive a 5/16 inch nut through a 19/64 inch counterbore. If you have a 19/64 inch transfer punch, that’s a dandy way to get the nuts out.
The easiest way to loosen the socket head cap screw holding the flex coupling to the leadscrew is to grab the coupling in a lathe chuck (with the leadscrew protruding into the headstock) and then apply the hex key:
Loosening leadscrew bolt
They used red (high-strength) Loctite on all the leadscrew bolts, as well as on the tapered joint between the leadscrew and the flex coupling, and on the bearing preload nut… so I will, too.
This case has a few refinements beyond that one, but it’s recognizably a descendant. The main changes:
The HT cable port on the side has a nice polygonal roof to reduce overhang
The serial connector sits in a recess to allow a thicker top plate
Smaller opening for the LEDs; I’ll get a window in this one, fer shure, yeah
4-40 screws hold the base plate on; setscrews may work and look better
Looks like I’ll be using blue filament for this version, having just discovered the last of the weird colors in the bottom of the 5 gallon bucket serving as a storage bin.
A view from the top:
Solid Model – Oblique Exploded Top
And from the base:
Solid Model – Oblique Exploded Base
The OpenSCAD source code:
// Wouxun KB-UV3D Battery Pack Case
// Ed Nisley KE4ZNU July 2012
include </home/ed/Thing-O-Matic/lib/MCAD/units.scad>
include </home/ed/Thing-O-Matic/Useful Sizes.scad>
// Layout options
Layout = "Show";
// Overall layout: Fit Show
// Printing plates: Build1 .. Buildn (see bottom!)
// Parts: TT3 Audio DSub Shell Base Top
// Shapes: RadioBase Contact
// Speaker-mic mount: PlugPlate
ShowGap = 10; // spacing between parts in Show layout
//- Extrusion parameters must match reality!
// Print with +1 shells and 3 solid layers
ThreadThick = 0.25;
ThreadWidth = 2.0 * ThreadThick;
HoleWindage = 0.2;
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
Protrusion = 0.1; // make holes end cleanly
//----------------------
// Dimensions
CaseOverallHeight = 31.5; // from battery surface, must clear PCBs!
CaseOverallWidth = 56;
CaseOverallLength = 80.25; // inside of base to end of compartment
BatteryClearance = 1.5; // contact seal height = air gap to compartment
// Interface to radio battery contacts
// Length = shell length
// calculated after everything else, so as to fill the compartment
ContactDia = 6.0; // use rounded contact for simplicity
ContactRecess = IntegerMultiple(0.75,ThreadThick); // recess for contact plate
ContactGapX = 10.5; // X space between contacts
Contact1Y = 52.5; // offset from base to edge of contact
Contact2Y = 56.5;
ContactStudDia = Clear4_40;
ContactStudHead = IntegerMultiple(Head4_40,ThreadWidth);
ContactStudHeadThick = Head4_40Thick;
PlateWidthMin = 53.0;
PlateWidthMax = 54.5;
PlateThick = IntegerMultiple(ContactRecess + ContactStudHeadThick,ThreadThick);
PlateAngle = atan(PlateThick/(PlateWidthMax/2 - PlateWidthMin/2));
echo("Battery plate thick: ",PlateThick);
// Offsets from battery surface to PCB centerlines
// TT3 must be above HT back shell for DB9 clearance
// These must cooperate with the numbers in the case shell module
TT3Offset = 17.5 + PlateThick;
AudioOffset = 4.0 + PlateThick;
// Plate interface to base alignment holes and notches
BaseWidthInner = PlateWidthMin;
BaseWidthOuter = CaseOverallWidth;
BaseLength = CaseOverallHeight; // perpendicular to battery surface
BaseThick = IntegerMultiple(1.0,ThreadThick); // minimum sheet thickness below teeth
BaseWidthTaper = 5.0; // ramp across entire width
BaseOpeningMax = 43.0;
BaseOpeningMin = 33.0;
BaseOpeningY = 5.3;
BaseOpeningDepth = IntegerMultiple(2.25,ThreadThick);
BaseTotalThick = BaseThick + BaseOpeningDepth;
echo("Base min thick: ",BaseThick," total: " ,BaseTotalThick);
BaseTabWidth = 6.0;
BaseTabThick = 2.0;
BaseTabGap = 7.0;
BaseTabOC = BaseTabWidth + BaseTabGap;
BaseToothSection = 3*BaseTabWidth + 2*BaseTabGap;
BaseToothBase = 5.8;
BaseToothTip = 2.8;
BaseToothThick = 2.0;
BaseToothAngle = atan(BaseOpeningDepth/0.6);
BaseToothOC = BaseTabOC;
WedgeAngle = atan(BaseWidthTaper/((BaseWidthOuter - BaseWidthInner)/2));
BaseEndLip = ThreadThick; // should be 0.25 mm or so
BaseEndWidth = (PlateWidthMin - 3*BaseToothBase - 2*BaseToothTip)/2;
BaseEndAngle = atan((BaseOpeningDepth - BaseEndLip)/BaseOpeningY);
SwitchBody = [8.6,3.7,3.3]; // mode switch
// Plate interface to HT battery latch, cables, and connectors
TopThick = IntegerMultiple(5.5,ThreadThick); // plate thickness for stiffness behind latch bar
echo("Top plate thick: ",TopThick);
DB9Recess = TopThick - 4.0; // recess to max TT3 PCB clearance behind DB9 plate
TabEngageLength = 1.6; // tab engaging surface length
TabWidth = 3.0; // ... width
TabEngageHeight = 4.5; // ... above battery compartment floor
TabHeight = 7.5; // tab ramp top above battery compartment floor
TabOC = 40.0;
LatchBarWidth = 3.4; // sliding latch mechanism (brass L stock)
LatchBarDepth = 3.4;
LatchBarThick = 0.35;
echo(" ... minimum: ",TopThick - LatchBarDepth);
SplitOffset = TT3Offset - 3.5;
TopBevel = 1.0; // bevel at top of battery compartment
TopBevelAngle = 45;
PinOffsetWidth = 2.5; // choose to center in sides of case shell
PinOffsetHeight = 13.5; // above baseplate bottom
PinDepth = 7.0; // into case shell
PinDia = 1.2;
ShellLength = CaseOverallLength - BaseThick - TopThick;
echo("Shell length: ",ShellLength);
// Speaker-mic plug plate
PlugBaseThick = 2.5; // recess depth
PlugFillThick = 3.0; // outer plate thickness
//----------------------
// 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);
}
//-------------------
// Component parts
//-----
// TinyTrak3+ PCB and component envelope
// Some dimensions should feed into the case shell, but don't
module TinyTrak3(Length = 1.0) {
PCBThick = 1.6;
PCBWide = 36.5;
TopHigh = 9.5;
TopWide = PCBWide - 1.5;
BotHigh = 2.5;
BotWide = 35.0;
PCBx = PCBWide/2;
PCBy = (PCBThick + HoleWindage)/2;
URx = TopWide/2;
URy = PCBy + TopHigh;
LRx = BotWide/2;
LRy = PCBy + BotHigh;
linear_extrude(height=Length,center=false,convexity=2) {
polygon(points=[[URx,URy],[URx,PCBy],[PCBx,PCBy],[PCBx,-PCBy],[LRx,-PCBy],[LRx,-LRy],
[-LRx,-LRy],[-LRx,-PCBy],[-PCBx,-PCBy],[-PCBx,PCBy],[-URx,PCBy],[-URx,URy]
]);
}
}
//-----
// Interface PCB and component envelope
// Some dimensions should feed into the case shell, but don't
module AudioInterface(Length = 1.0) {
PCBThick = 2.0;
PCBWide = 49.5;
TopHigh = 9.0 + Protrusion;
TopWide = 46.0;
BotHigh = 3.0;
BotWide = 44.0;
PCBx = PCBWide/2;
PCBy = (PCBThick + HoleWindage)/2;
URx = TopWide/2;
URy = PCBy + TopHigh;
LRx = BotWide/2;
LRy = PCBy + BotHigh;
linear_extrude(height=Length,center=false,convexity=2) {
polygon(points=[[URx,URy],[URx,PCBy],[PCBx,PCBy],[PCBx,-PCBy],[LRx,-PCBy],[LRx,-LRy],
[-LRx,-LRy],[-LRx,-PCBy],[-PCBx,-PCBy],[-PCBx,PCBy],[-URx,PCBy],[-URx,URy]
]);
}
}
//-----
// DB-9 (DE-9) panel opening
// http://www.interfacebus.com/Connector_D-Sub_Mechanical_Dimensions.html
// DB-9 shell mounts on outside surface of case
// This is for the solder terminal side
module DSubMin9(Length = 1.0) {
Holex = 0.984/2 * inch;
HoleDia = Tap4_40;
URx = 0.769/2 * inch;
URy = 0.432/2 * inch;
linear_extrude(height=Length,center=false,convexity=3) {
polygon(points=[[URx,URy],[URx,-URy],[-URx,-URy],[-URx,URy]]);
for (x = [-1,1]) {
translate([x*Holex,0,0])
rotate(45) circle(r=(HoleDia + HoleWindage)/2,$fn=4);
}
}
}
//-----
// Central case shape
// This *should* depend directly on the circuit board sizes, but doesn't
// The "Offset" parameters attempt to bottle up all the board sizes
// Support in LED window must be hand-fit to work correctly... and isn't needed!
module CaseShell(Length=(ShellLength),Holes="true") {
// Polygon coordinates are in XY plane
URx = 40.0/2;
URy = CaseOverallHeight;
MRx = CaseOverallWidth/2;
MRy = 15.0;
LRx = CaseOverallWidth/2;
LRy = (LRx - PlateWidthMin/2)*tan(PlateAngle);
BRx = PlateWidthMax/2;
BRy = PlateThick - 0*Protrusion;
PRx = PlateWidthMin/2; // combined battery plate
PRy = 0;
ScrewOffset = 20.0; // from top end of case
LEDWindow = [26.0,5.0,6]; // with case aligned vertically
LEDOffset = [15,URy,(Length + TopThick - 25.0)];
TrimPot1 = [-14,TT3Offset,(Length + TopThick - 30)];
TrimPot2 = [-14,TT3Offset,(Length + TopThick - 37.5)];
HTCableDia = 3.5;
HTCableOffset = AudioOffset + HTCableDia/2 + 1.0;
rotate([90,0,180])
union() {
difference() {
linear_extrude(height=Length,center=false,convexity=5)
polygon(points=[[URx,URy],[MRx,MRy],[LRx,LRy],[BRx,BRy],[PRx,PRy],
[-PRx,PRy],[-BRx,BRy],[-LRx,LRy],[-MRx,MRy],[-URx,URy]]);
if (Holes) {
translate([0,AudioOffset,-Protrusion])
AudioInterface(Length + 2*Protrusion);
translate([0,TT3Offset,-Protrusion])
TinyTrak3(Length + 2*Protrusion);
for (y = [TT3Offset,AudioOffset])
translate([-CaseOverallWidth,y,(Length - ScrewOffset)])
rotate([0,90,0])
rotate(0) // Z rotation puts point upward for printing
PolyCyl(Tap4_40,CaseOverallWidth);
translate(LEDOffset)
rotate([90,90,0])
translate([-LEDWindow[0]/2,-LEDWindow[1]/2,-Protrusion])
cube(LEDWindow,center=false);
for (p = [TrimPot1,TrimPot2])
translate(p)
rotate([-90,90,0]) // Y rotation puts point upward for printing
PolyCyl(3.0,URy);
for (x=[-1,1]) {
translate([x*(CaseOverallWidth/2 - PinOffsetWidth),
PinOffsetHeight,
(Length - PinDepth)])
rotate(45) // align hole sides with case sides
PolyCyl(PinDia,2*TopThick);
translate([x*(CaseOverallWidth/2 - PinOffsetWidth),
PinOffsetHeight,
-PlateThick])
rotate(45) // align hole sides with case sides
PolyCyl(PinDia,(PlateThick + PinDepth));
}
for (x=[-1,1]) // setscrews to secure base plate
translate([x*(CaseOverallWidth/2 - 3*Tap4_40),
TT3Offset,-Protrusion])
rotate(360/(5*4))
PolyCyl(Tap4_40,2*TopThick);
translate([-(ContactGapX/2 + ContactDia/2),0,(Contact1Y + ContactDia/2)])
rotate([90,0,0])
Contact();
translate([+(ContactGapX/2 + ContactDia/2),0,(Contact2Y + ContactDia/2)])
rotate([90,0,0])
Contact();
translate([CaseOverallWidth/2,HTCableOffset,(Length - HTCableDia/4)])
rotate([0,90,0])
cube([(HTCableDia/2 + Protrusion),HTCableDia,CaseOverallWidth],center=true);
translate([0,HTCableOffset,(Length - HTCableDia/2)])
rotate([0,90,0])
cylinder(r=(1/cos(30))*HTCableDia/2,h=CaseOverallWidth,$fn=6);
}
}
if (false)
if (Holes)
translate(LEDOffset) // support plug in LED window
rotate([90,90,0])
translate([-0.95*LEDWindow[0]/2,-0.80*LEDWindow[1]/2,ThreadWidth/2])
cube([0.95*LEDWindow[0],0.80*LEDWindow[1],2*ThreadWidth],center=false);
}
}
//-----
// Battery contact recess
// This gets subtracted from the bottom plate in two places
// Align points to print upward
module Contact() {
if (true)
union() { // vertical printing with case
translate([0,0,-(ContactRecess + Protrusion)/2])
PolyCyl(ContactDia,(ContactRecess + Protrusion),8);
translate([0,0,-(PlateThick + Protrusion)])
rotate(60/2)
PolyCyl(ContactStudDia,PlateThick,6);
translate([0,0,-(ContactRecess + ContactStudHeadThick/3)])
PolyCyl(ContactStudHead,ContactStudHeadThick,8); // allow for solder blob
}
else
union() { // horizontal printing alone
translate([0,0,-(ContactRecess - Protrusion)/2])
PolyCyl(ContactDia,(ContactRecess + Protrusion),8);
translate([0,0,-(PlateThick + Protrusion)])
PolyCyl(ContactStudDia,(PlateThick + 2*Protrusion));
translate([0,0,-(ContactRecess + ContactStudHeadThick/3)])
PolyCyl(ContactStudHead,ContactStudHeadThick,8); // allow for solder blob
}
}
//-----
// Radio bottom locating feature
// This polygon gets subtracted from the battery pack base
module RadioBase() {
linear_extrude(height=(BaseOpeningDepth + Protrusion),center=false,convexity=5)
polygon(points=[
[-BaseOpeningMax/2,-Protrusion],
[-BaseOpeningMin/2,BaseOpeningY],
[-(BaseToothOC/2 + BaseToothBase/2),BaseOpeningY],
[-(BaseToothOC/2 + BaseToothTip/2),(BaseOpeningY - BaseToothThick)],
[-(BaseToothOC/2 - BaseToothTip/2),(BaseOpeningY - BaseToothThick)],
[-(BaseToothOC/2 - BaseToothBase/2),BaseOpeningY],
[ (BaseToothOC/2 - BaseToothBase/2),BaseOpeningY],
[ (BaseToothOC/2 - BaseToothTip/2),(BaseOpeningY - BaseToothThick)],
[ (BaseToothOC/2 + BaseToothTip/2),(BaseOpeningY - BaseToothThick)],
[ (BaseToothOC/2 + BaseToothBase/2),BaseOpeningY],
[ BaseOpeningMin/2,BaseOpeningY],
[ BaseOpeningMax/2,-Protrusion],
[ (BaseTabOC + BaseTabWidth/2),-Protrusion],
[ (BaseTabOC + BaseTabWidth/2),BaseTabThick],
[ (BaseTabOC - BaseTabWidth/2),BaseTabThick],
[ (BaseTabOC - BaseTabWidth/2),-Protrusion],
[ BaseTabWidth/2,-Protrusion],
[ BaseTabWidth/2,BaseTabThick],
[-BaseTabWidth/2,BaseTabThick],
[-BaseTabWidth/2,-Protrusion],
[-(BaseTabOC + BaseTabWidth/2),-Protrusion],
[-(BaseTabOC + BaseTabWidth/2),BaseTabThick],
[-(BaseTabOC - BaseTabWidth/2),BaseTabThick],
[-(BaseTabOC - BaseTabWidth/2),-Protrusion],
],
convexity=5
);
}
//-----
// Battery pack base
module Base() {
difference() {
rotate([-90,180,0]) // main case shape
CaseShell(BaseTotalThick,false);
translate([0,0,BaseThick]) // radio base interface
RadioBase();
translate([0,0,BaseThick]) // tooth bevel
rotate([(-90 + BaseToothAngle),0,0])
translate([0,-0.5,0])
cube([(BaseToothSection + 2*Protrusion),1.0,10],center=true);
translate([-BaseWidthOuter, // surface slope
-(BaseThick + BaseEndLip)/tan(BaseEndAngle),0])
rotate([BaseEndAngle,0,0])
difference() {
cube([2*BaseWidthOuter,3*BaseOpeningY,BaseOpeningDepth],center=false);
translate([(BaseWidthOuter - (BaseToothSection + 2*Protrusion)/2),0,0])
cube([(BaseToothSection + 2*Protrusion),1.2*BaseOpeningY,BaseOpeningDepth],center=false);
}
for (x=[-1,1]) // alignment pin holes
translate([x*(CaseOverallWidth/2 - PinOffsetWidth),PinOffsetHeight,-Protrusion])
rotate(45) // align hole side with plate side
PolyCyl(PinDia,2*TopThick);
for (x=[-1,1]) // mounting setscews
translate([x*(CaseOverallWidth/2 - 3*Tap4_40),
TT3Offset,-Protrusion])
rotate(-360/(-5*4))
PolyCyl(Tap4_40,2*TopThick);
translate([(-SwitchBody[0]/2),TT3Offset,-SwitchBody[2]/2]) // mode switch
scale([1,1,2])
cube(SwitchBody);
}
}
//-----
// Top plate with latch
// Split around TinyTrak3 serial connector
// ... which must be at the same height as in the shell!
// The cable hole sizes & locations are entirely ad-hoc
module TopPlate() {
Cable1Dia = 5.0;
Cable2Dia = 5.0;
CableHoleLength = TopThick + 2*Protrusion;
CableHoleZ = -Protrusion;
DB9Plate = [32.0,13.5,1.25]; // plate surrounding connector body
difference() {
rotate([-90,180,180])
CaseShell(TopThick,false);
translate([0,-TT3Offset,-Protrusion])
DSubMin9(TopThick + 2*Protrusion);
translate([0,-TT3Offset,(TopThick - DB9Plate[2]/2)])
cube([DB9Plate[0],DB9Plate[1],(DB9Plate[2] + Protrusion)],center=true);
translate([-CaseOverallWidth,-SplitOffset,-2*Protrusion]) // split the plate
cube([2*CaseOverallWidth,4*Protrusion,(TopThick + 2*Protrusion)]);
translate([0,0,(TopThick - TopBevel)])
rotate([-TopBevelAngle,0,0])
translate([-CaseOverallWidth,-TopThick,0])
cube([2*CaseOverallWidth,2*TopThick,2*TopThick],center=false);
for (x=[-1,1])
translate([(x*TabOC/2),
(-TabHeight/2 + Protrusion),
(TopThick - TabEngageLength/2 + Protrusion/2)])
rotate([90,0,0])
cube([TabWidth,
(TabEngageLength + Protrusion),
(TabHeight + Protrusion)],center=true);
translate([-CaseOverallWidth,
-(TabEngageHeight + LatchBarWidth - BatteryClearance),
(TopThick - LatchBarDepth)])
cube([2*CaseOverallWidth,(LatchBarWidth + LatchBarThick),(LatchBarDepth + Protrusion)]);
for (x=[-1,1])
translate([(x*CaseOverallWidth/4),
-(TabEngageHeight + LatchBarWidth + Clear2_56/2 - BatteryClearance + Protrusion),
0]) {
translate([0,0,-Protrusion])
rotate(45) // align sides with slot
PolyCyl(Tap2_56,(TopThick + 2*Protrusion));
translate([0,0,(TopThick - LatchBarDepth)])
rotate(60) // align sides with slot
PolyCyl((Head2_56 + Protrusion),TopThick,6); // extra extra clearance
}
for (x=[-1,1])
translate([x*(CaseOverallWidth/2 - PinOffsetWidth),-PinOffsetHeight,-Protrusion])
rotate(45) // align hole side with plate side
PolyCyl(PinDia,2*TopThick);
for (x=[-1,1]) // coincidentally line up with latch tabs
translate([(x*TabOC/2),-(SplitOffset - 3.0),-Protrusion])
scale([1,1.7,1])
PolyCyl(Cable1Dia,CableHoleLength,6);
}
}
//-----
// Speaker-Mic plug mounting plate
module PlugPlate() {
JackOC = 11.20; // 14.25 OD - (3.58 + 2.58)/2
JackScrewDia = 4.6;
JackScrewOffsetX = 1.00;
JackScrewOffsetY = 5.25; // mounting screw to edge of lower recess
PlugBaseWidth = 9.25; // lower section of plate
PlugBaseLength = 22.0;
PlugBaseRadius = 1.75;
Plug3Offset = 5.25; // edge of base recess to 3.5 mm jack
Plug2BezelDia = 7.1; // 2.5 mm plug
Plug2BezelThick = 1.04;
Plug2ScrewDia = 6.0;
Plug3ScrewLength = 3.0;
Plug3BezelDia = 8.13; // 3.5 mm plug
Plug3BezelThick = 1.6;
Plug3ScrewDia = 7.95;
Plug3ScrewLength = 4.0;
PlugFillOffsetX = JackScrewOffsetX - 0.5; // base recess CL to fill CL
PlugFillOffsetY = -10.5; // ... to edge of fill plate
PlugFillWidth = 11.0;
PlugFillLength = 34.00;
PlugFillRadius1 = 1.5;
PlugFillRadius2 = 4.5;
PlugFillOffsetYTotal = 0;
BaseX = PlugBaseWidth/2 - PlugBaseRadius;
BaseY = PlugBaseLength/2 - PlugBaseRadius;
difference() {
union() {
linear_extrude(height=PlugBaseThick,center=false,convexity=3)
hull() {
translate([-BaseX,-BaseY,0])
circle(r=PlugBaseRadius,$fn=8);
translate([-BaseX, BaseY,0])
circle(r=PlugBaseRadius,$fn=8);
translate([ BaseX, BaseY,0])
circle(r=PlugBaseRadius,$fn=8);
translate([ BaseX,-BaseY,0])
circle(r=PlugBaseRadius,$fn=8);
}
translate([PlugFillOffsetX,
(PlugFillLength/2 - PlugBaseLength/2 + PlugFillOffsetY),
PlugBaseThick])
linear_extrude(height=PlugFillThick,center=false,convexity=5)
hull() {
translate([0,-(PlugFillLength/2 - PlugFillRadius2),0])
circle(r=PlugFillRadius2,$fn=10);
translate([-(PlugFillWidth/2 - PlugFillRadius1),-PlugBaseLength/2,0])
circle(r=PlugFillRadius1,$fn=8);
translate([-(PlugFillWidth/2 - PlugFillRadius1),
(PlugFillLength/2 - PlugFillRadius1),0])
circle(r=PlugFillRadius1,$fn=8);
translate([(PlugFillWidth/2 - PlugFillRadius1),
(PlugFillLength/2 - PlugFillRadius1),0])
circle(r=PlugFillRadius1,$fn=8);
translate([(PlugFillWidth/2 - PlugFillRadius1),-PlugBaseLength/2,0])
circle(r=PlugFillRadius1,$fn=8);
}
}
translate([0,-JackOC/2,-Protrusion])
rotate(360/16) {
PolyCyl(Plug3BezelDia,(Plug3BezelThick + Protrusion),8);
PolyCyl(Plug3ScrewDia,(PlugBaseThick + PlugFillThick + 2*Protrusion),8);
}
translate([0,+JackOC/2,-Protrusion])
rotate(360/16) {
PolyCyl(Plug2BezelDia,(Plug2BezelThick + Protrusion),8);
PolyCyl(Plug2ScrewDia,(PlugBaseThick + PlugFillThick + 2*Protrusion),8);
}
translate([JackScrewOffsetX,-(PlugBaseLength/2 + JackScrewOffsetY),0])
PolyCyl(JackScrewDia,(PlugBaseThick + PlugFillThick + Protrusion));
}
}
//-------------------
// Build things...
ShowPegGrid();
if (Layout == "TT3")
TinyTrak3();
if (Layout == "Audio")
AudioInterface();
if (Layout == "DSub")
DSubMin9();
if (Layout == "Shell")
CaseShell(CaseOverallLength);
if (Layout == "Top")
TopPlate();
if (Layout == "Base")
Base();
if (Layout == "RadioBase")
RadioBase();
if (Layout == "PlugPlate")
PlugPlate();
if (Layout == "Contact")
rotate([180,0,0])
Contact();
if (Layout == "Show" || Layout == "Fit") {
translate([0,-ShellLength/2,0]) {
translate([0,(Layout == "Show")?-ShowGap:0,0])
rotate([90,0,0])
color("SandyBrown") Base();
translate([0,0,0])
color("LightGreen") render() CaseShell();
translate([-(CaseOverallWidth/2 + 10),50,CaseOverallHeight/2])
rotate([0,-90,0])
color("Gold") PlugPlate();
translate([0,((Layout == "Show")?(ShellLength + ShowGap):ShellLength),0])
rotate([-90,0,0])
color("BurlyWood") TopPlate();
}
}
if (Layout == "Build1") {
translate([5 + CaseOverallHeight,0,0])
rotate([0,0,90])
Base();
translate([-(5 + CaseOverallHeight),0,0])
rotate(90)
TopPlate();
}
if (Layout == "Build2") {
translate([0,-CaseOverallHeight/2,ShellLength])
rotate([-90,0,0])
CaseShell();
}
if (Layout == "Build3") {
translate([0,0,(PlugBaseThick + PlugFillThick)])
rotate([180,0,0])
PlugPlate();
}
U2, the MAX4544 data/voice mux, runs from the shunt-regulated +5 V, not the TT3+ regulator
Miscellaneous doc cleanup
I’m mulling over a capacitor between the TT3+ data output and the earbud, so as to monitor transmissions, but I’m not convinced that’s worthwhile.
The PCB layout, with wire jumpers on the two inner layers:
Wouxun KG-UV3D GPS+Voice PCB
The previous version doesn’t look much different from what this one will become:
GPS-HT Wouxun interface – brassboard
This will replace the ICOM Z-1A radio and GPS interface on Mary’s bike, which has been working fine for quite a while. That can’t last, so I’m trying to get ahead of the failure curve…
The flash mob was here and gone within the span of an hour:
View spike for Moen faucet post – 2012-04-05
Does Yahoo! Image Search have something like a featured image of the hour? I can’t find anything obvious, but I cannot imagine what else would cause that many views of a single page that lacks buck-naked celebrities, jackass stunts, or hideously embarrassing personal revelations.
Given that all of their “trending image searches” show (typically female) human faces, I doubt that the grubby innards of a faucet would appear in that gallery.
Back when I got a Philips Sonicare (on the recommendation of my dental hygenist, after a particularly nasty bout of plaque removal), the battery gave nearly two weeks of service between charges. As shown in that graph, the runtime gradually faded away to two days, at which point I decided it was time to tear the thing apart and see about replacing the batteries.
The instruction manual tells how to dismantle the case and extract the NiCd battery for recycling:
Please note that this process is NOT reversible.
Well, there’s a challenge if I ever read one, but Wouldn’t It Be Nice If you could take something apart, unplug its defunct battery, install a new one, and button it up again? Then you wouldn’t be forced to buy a new $70 toothbrush, which probably explains everything… and I suppose the replacement battery would cost $40, even if it were a pair of AA cells.
For reference, the instructions (clicky for more dots):
As predicted, suasion applied through a small screwdriver popped the top end of the case apart, but the remainder required concerted prying and muttering. The case halves mate with a tongue-and-groove joint that’s either sonic welded or adhesive bonded to form a watertight seal all the way around, to the extent that they suggested cleaning the thing in a dishwasher.
Eventually, though, it came apart:
Sonicare – case opened
The “motor” (actually, a solenoid that couples to the magnet on the brush stem) is firmly potted in place (on the right), as are the NiCd cells and the charging power pickup coil at the base on the left. The potting compound seems to be a clear epoxy, rather than a compliant rubber, and it doesn’t bond to the case at all. It is, however, a perfect fit and doesn’t pop loose without a struggle; their instructions will definitely break the PCB.
Seen from the other direction, six connections join the PCB to those immovable objects. The four pins (on the far left) go to the solenoid and the pair (just to their right) to the battery:
Sonicare PCB solder points
A few dabs of desoldering wick suffice to free the pins and release the PCB. Mercifully, the potting compound surrounding the charging coil slid out easily, as they (inexplicably) omitted a mechanical lock molded into the case:
Sonicare – PCB removed
Removing the NiCd cells required considerable prying, as described in the instructions, that en passant damaged their cases. I think if you weren’t paying attention, you could easily rupture a cell case with the screwdriver and spatter the area with potassium hydroxide, perhaps shorting the cell in the process and producing rather more excitement than most folks expect.
A closeup of one cell; the other bears similar damage:
Sonicare – damaged NiCd cells
I snipped off the cell tabs and applied them to the new NiMH cells. A bit of closed-cell foam between the cells and the PCB cushions the assembly:
Sonicare – new NiMH cells on PCB
Stacking more foam snippets under the cells filled the space left by the potting compound, then soldering the solenoid pins held everything together:
Sonicare – new NiMH in place
A wrap of clear adhesive (rather than the obligatory Kapton) makes for a tidy joint that probably won’t last very long, but it looks much the way it did before the operation. The case is no longer waterproof and won’t withstand the dishwasher. In fact, I must now store it with the brush end downward to keep the last few drops out of the handle.
There’s an interesting solder jumper on the PCB that I didn’t bridge, but the next time it’s opened up I’ll apply a dab:
Sonicare – BLINKY jumper
The alert reader will notice that I’ve replaced 2000 mA·h AA NiCd cells with 600 mA·h 2/3 AANiMH cells, without changing the charger. The power transfer through the inductive coupling drives a trickle charger at about one hour of recharge per brushing, so there’s not much danger of overcharging the cells.
Now, to discover what runtime fresh cells deliver. This calls for another slip of geek scratch paper in the bathroom.
Being that type of guy, I noted each date when my Sonicare toothbrush needs recharging, at least after the battery had declined to about a week between charges, specifically so I could produce this graph:
Sonicare Runtime
The peaks include trips where I didn’t use the toothbrush and I’ve certainly blundered a few dates, but you can eyeball a trendline: those cells are kaput!
In round numbers, I bought the thing in early 2010, so the cells lasted maybe 2-½ years. I routinely run the toothbrush until the blinky light indicates that it needs charging, then fill it up overnight, to avoid having the cells fail like the ones in the beard trimmer.
Somehow the notion of discarding the whole toothbrush seems wrong, even though the instruction manual describes how to remove the battery for recycling before you junk the carcass. Talk about planned obsolescence!