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.

Tour Easy: Anker 20K V2 USB Power Bank

After five years, it’s time to replace the Anker 13000 mA·hr USB power banks / chargers I used with the M20 cameras and then the C100 cameras:

SJCAM M20 Mount - Tour Easy side view
SJCAM M20 Mount – Tour Easy side view

The Anker 325 20K V2 power bank is considerably chunkier, as befits its 20,000 mA·hr cell capacity (although the fine print says 12,500 mA·hr output):

Anker 20K V2 Power Bank - installed
Anker 20K V2 Power Bank – installed

The white tape stripe on the top marks the USB port on the end to reduce the fumbling involved in an out-of-sight socket. There’s also a USB-C port on that end for both charging the pack and powering other devices.

The new mounting cradle descends directly from the 13000 cradle:

Anker 325 20KV2 Power Bank - slicer preview
Anker 325 20KV2 Power Bank – slicer preview

The model includes a projection of the battery on the XY plane for export to an SVG file suitable for laser-cutting an EVA foam pad to cushion the bumps.

The OpenSCAD source code as a GitHub Gist:

// Anker PowerCore 325 20K V2 Power Bank
// Ed Nisley – KE4ZNU
// 2024-07
/* [Layout Options] */
Layout = "Show"; // [Show,Build]
Part = "Cradle"; // [Cradle,Battery,Pad]
/* [Extrusion Parameters] */
ThreadWidth = 0.40;
ThreadThick = 0.25;
HoleWindage = 0.2;
Protrusion = 0.1;
//—–
// Dimensions
/* [Hidden] */
ID = 0;
OD = 1;
LENGTH = 2;
EmbossDepth = 2*ThreadThick + Protrusion; // recess depth + Protrusion beyond surface
DebossHeight = EmbossDepth; // text height + Protrusion into part
Projection = 10; // stick-out to punch through shell sides & suchlike
FadeColor = "Green";
FadeAlpha = 0.25;
//—–
// Useful routines
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
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);
}
//—–
// Battery
// Based on Anker PowerCore 325, simplified shapes
// Includes port punchouts
Battery = [162.0+0.5,81.5+0.5,24.0]; // X=length, Y=max, Z=max
module BatteryShape(Jacks = true) {
USB = [[Projection,20,12],[Projection,18,10]]; // clearance around USB output jacks
USBOffset = [[0,20.0,0],[0,62.5,0]]; // from -Y edge to center of jack, Z centered
BatteryRad = 7.0; // corner rounding radius
BatterySides = 2*3*4;
hull()
for (i=[-1,1], j=[-1,1])
translate([i*(Battery.x/2 – BatteryRad),
j*(Battery.y/2 – BatteryRad),
0])
cylinder(r=BatteryRad,h=Battery.z,$fn=BatterySides,center=true);
if (Jacks)
for (i=[0,len(USB)-1])
translate([(Battery.x + USB[i].x)/2 – Protrusion,-Battery.y/2 + USBOffset[i].y,0])
cube(USB[i],center=true);
}
//—–
// Battery cradle
RackWidth = 90.0; // flat width between rack rails
CradleWall = [4.0,4.0,3.0]; // wall thickness
CradleRadius = 2.0; // corner rounding
CradlePad = 1.0; // cushion on battery bottom
BatteryBase = CradleWall.z + CradlePad; // actual bottom surface of battery
CradleOA = [Battery.x + 2*CradleWall.x,
min((Battery.y + 2*CradleWall.y),RackWidth),
BatteryBase + Battery.z/2];
echo(str("Cradle OA: ",CradleOA));
module Cradle() {
difference() {
hull()
for (i=[-1,1], j=[-1,1]) { // box with tidy rounded corners
translate([i*(CradleOA.x/2 – CradleRadius),
j*(CradleOA.y/2 – CradleRadius),
1*(CradleOA.z – CradleRadius)])
sphere(r=CradleRadius,$fn=6);
translate([i*(CradleOA.x/2 – CradleRadius),
j*(CradleOA.y/2 – CradleRadius),
0*(CradleOA.z/2 – CradleRadius)])
cylinder(r=CradleRadius,h=CradleOA.z/2,$fn=6);
}
translate([0,0,Battery.z/2 + BatteryBase]) // minus the battery
minkowski(convexity=3) { // … slightly embiggened
BatteryShape();
cube(2*CradlePad,center=true);
}
translate([0,0,CradleWall.z – ThreadThick + Protrusion/2]) // recess top legend
cube([55,20,EmbossDepth],center=true);
translate([0,0,(EmbossDepth – Protrusion)/2]) // recess bottom legend
cube([70,15,EmbossDepth],center=true);
}
translate([0,4.0,CradleWall.z – DebossHeight – Protrusion])
linear_extrude(height=DebossHeight,convexity=20)
text(text="PowerCore",size=6,spacing=1.20,
font="Arial:style:Bold",halign="center",valign="center");
translate([0,-4.0,CradleWall.z – DebossHeight – Protrusion])
linear_extrude(height=DebossHeight,convexity=20)
text(text="20K V2",size=6,spacing=1.20,
font="Arial:style:Bold",halign="center",valign="center");
linear_extrude(height=DebossHeight,convexity=20)
mirror([0,1,0])
text(text="KE4ZNU",size=10,spacing=1.20,
font="Arial:style:Bold",halign="center",valign="center");
}
//—–
// Build things
// Layouts for design & tweaking
if (Layout == "Show")
if (Part == "Battery")
BatteryShape();
else if (Part == "Cradle") {
Cradle();
translate([0,0,Battery.z/2 + CradleWall.z])
color(FadeColor,FadeAlpha)
BatteryShape();
}
else if (Part == "Pad")
linear_extrude(height=CradlePad)
projection(cut=true)
BatteryShape(Jacks = false);
// Build layouts for top-level parts
if (Layout == "Build") {
if (Part == "Cradle")
Cradle();
if (Part == "Pad")
projection(cut=true)
BatteryShape(Jacks = false);
}