169 lines
6.6 KiB
OpenSCAD
169 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 = [
|
|
[7, 14, 0, 0, 0.25*25.4, yappCircle],
|
|
[25, 35, 0, 0, 0.125*25.4, yappCircle],
|
|
];
|
|
|
|
//---------------------------------------------------------------
|
|
// 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 = 2.6; // mm proud of the front face
|
|
plateEmbed = 1.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.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();
|