Files
xiao-dfplayer/speakerbox.scad
T

173 lines
6.6 KiB
OpenSCAD

//-----------------------------------------------------------------------
// Speaker enclosure - 4cm x 5cm x 10cm exterior, 4.5cm speaker opening
// Built with YAPP_Box (YAPPgenerator_v3.scad)
//-----------------------------------------------------------------------
include <./YAPPgenerator_v3.scad>
printBaseShell = true;
printLidShell = true;
// Reference "PCB" - there's no real PCB here, this block just defines
// the box's internal footprint. Exterior = pcbLength/pcbWidth + 2*wallThickness
// (padding = 0), so: 36 + 2*2 = 40mm, 46 + 2*2 = 50mm.
pcbLength = 40; // X axis (front-to-back) -> 4cm exterior
pcbWidth = 50; // Y axis (side-to-side) -> 5cm exterior
pcbThickness = 1.6;
standoffHeight = 0;
standoffDiameter = 0;
standoffPinDiameter = 0;
pcb = [
["Main", pcbLength, pcbWidth, 0, 0, pcbThickness,
standoffHeight, standoffDiameter, standoffPinDiameter, 0.4]
];
paddingFront = 0;
paddingBack = 0;
paddingRight = 0;
paddingLeft = 0;
wallThickness = 2.0;
basePlaneThickness = 2.0;
lidPlaneThickness = 2.0;
// Total exterior height = basePlaneThickness + baseWallHeight
// + lidWallHeight + lidPlaneThickness
// = 2 + 86 + 10 + 2 = 100mm (10cm)
baseWallHeight = 86;
lidWallHeight = 10;
ridgeHeight = 5.0;
roundRadius = 3.0;
//---------------------------------------------------------------
// Speaker cutout - centered on the Front face (the 5cm x 10cm face)
// Front face local coords (yappCoordBox, corner-referenced):
// p(0) = position from the Left edge (Y axis)
// p(1) = position from the Bottom edge (Z axis)
// A 45mm circle centered at Y=25, Z=50 has its bounding-box corner at:
// p1 = 50 - 22.5 = 27.5
//---------------------------------------------------------------
cutoutsFront = [
[2.5, 2.5, 0, 0, 22.5, yappCircle]
];
cutoutsLid = [
[22, 10, 0, 0, 0.5*25.4/2, yappCircle],
[2, 35, 0, 0, 0.5*25.4/2, yappCircle],
];
snapJoins = [
[10,5,yappFront,yappBack,yappSymmetric]
];
//---------------------------------------------------------------
// Angled speaker-retaining wall
// A near-vertical rib that rises 30mm from the front-bottom of
// the base and leans slightly back toward the box centre. Its
// speaker-facing surface sits 15mm behind the front (speaker)
// wall at the floor and 17.5mm behind it at the top, so it
// backstops the speaker and holds it against the speaker hole.
//---------------------------------------------------------------
frontInnerX = shellInsideLength + wallThickness; // X of inner front-wall face
retainGapBot = 15; // mm behind the front wall at the floor
retainGapTop = 17.5; // mm behind the front wall at the top
retainHeight = 30; // rib height above the base floor
retainThick = 2.4; // rib wall thickness
retainWidth = 40; // Y span (a little wider than the speaker)
retainYc = 27; // Y centre (matches the speaker cutout)
retainFoot = 10; // how far the base flares back toward centre
retainFootH = 14; // height over which the flare tapers back in
module speakerRetainer()
{
xBot = frontInnerX - retainGapBot;
xTop = frontInnerX - retainGapTop;
zBot = basePlaneThickness;
zTop = basePlaneThickness + retainHeight;
// hookBaseInside() origin sits at the inner corner:
// global = hookCoord + [wallThickness, wallThickness, basePlaneThickness]
// X grows toward the speaker hole; the flared foot extends the other
// way (toward box centre) so it never touches the speaker. Each layer
// sits fully on the one below it, so it prints without support.
translate([-wallThickness, -wallThickness, -basePlaneThickness])
translate([0, retainYc + retainWidth/2, 0])
rotate([90, 0, 0])
linear_extrude(height = retainWidth)
polygon([[xBot + retainThick, zBot], // front face, floor
[xBot - retainFoot, zBot], // flared foot toe
[xTop, zBot + retainFootH], // foot tapers into back face
[xTop, zTop], // back face, top
[xTop + retainThick, zTop]]); // front face, top
}
module hookBaseInside()
{
speakerRetainer();
}
//---------------------------------------------------------------
// Skull faceplate / grille
// A round faceplate, raised proud of the front face, that fully
// overlaps the 45mm speaker opening and fuses to the solid front
// wall around it. A skull face is cut through it as the speaker
// grille - eye sockets and nasal opening come straight from the
// icon, plus a row of added tooth slots in the jaw.
// skull.svg: "death-skull" by sbed / game-icons.net - CC BY 3.0
// https://game-icons.net/1x1/sbed/death-skull.html
//---------------------------------------------------------------
plateDia = 50; // faceplate diameter (> 45mm opening -> fused rim)
plateRaise = 1; // mm proud of the front face
plateEmbed = 5; // mm the plate sinks into the front wall (weld)
skullFaceW = 46; // skull width across the plate
skullMaskD = 44; // opened-up disc around the skull -> the grille voids
frontOuterX = shellInsideLength + 2*wallThickness; // X of the outer front face
speakerYc = 27; // speaker opening centre (Y)
speakerZc = 28.6; // speaker opening centre (Z)
// skull.svg imports at ~180.6mm wide (512-unit viewBox at 72dpi)
skullImportW = 180.6;
module skullArt() { import("skull-2.svg", center = true); }
// The faceplate is a solid disc. The grille is the skull's negative
// space: inside a centre disc, everything that is NOT skull bone is
// opened up - eye sockets, nasal opening and the crescent gaps around
// the cranium and jaw. The bone itself stays as plate material, so the
// disc is never cut through and the skull reads by its voids.
module grille2D()
{
difference()
{
circle(d = plateDia, $fn = 160);
difference()
{
circle(d = skullMaskD, $fn = 150);
scale(skullFaceW / skullImportW) skullArt();
}
// teeth: a row of slots cut into the jaw for extra grille area
//for (i = [-2 : 2])
//translate([i * 4.4, -15.5]) square([2.2, 7], center = true);
}
}
module skullFaceplate()
{
// hookBaseOutside() shares the inner-corner origin:
// global = hookCoord + [wallThickness, wallThickness, basePlaneThickness]
translate([-wallThickness, -wallThickness, -basePlaneThickness])
translate([frontOuterX - plateEmbed, speakerYc, speakerZc])
rotate([90, 0, 90]) // 2D x->Y, 2D y->Z, extrude->+X
linear_extrude(plateRaise + plateEmbed)
grille2D();
}
module hookBaseOutside()
{
skullFaceplate();
}
showOrientation = true;
YAPPgenerate();