Added OpenSCAD files.

This commit is contained in:
ThorstenB 2022-05-17 00:06:31 +02:00
parent c16eb997bd
commit f43804582d
8 changed files with 990 additions and 1 deletions

View File

@ -0,0 +1,124 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
module torus(r1, r2)
{
rotate_extrude(convexity = 10)
translate([r2 + r1, 0, 0])
circle(r=r2);
}
module round_cylinder(fillet, r, h)
{
for(z=[fillet, h-fillet])
torus(r-2*fillet, fillet, center=[0,0,z]);
cylinder(r=r-fillet, h);
translate([0,0,fillet]) cylinder(r=r, h=h-2*fillet);
}
// Make a rectangle with rounded corners of given radius.
// The maximum outer dimensions exactly match the given width/height.
module roundedCube(Width, Height, Depth, CornerRadius)
{
$fn=36;
union()
{
for (x=[0,Width-CornerRadius*2])
for (y=[0,Height-CornerRadius*2])
translate([x+CornerRadius, y+CornerRadius, 0]) cylinder(r=CornerRadius, h=Depth);
translate([CornerRadius,0,0]) cube([Width - 2*CornerRadius, Height, Depth]);
translate([0,CornerRadius,0]) cube([Width, Height - 2*CornerRadius, Depth]);
}
}
module cylinderLedge(r, length)
{
$fn=36;
translate([0, 0, -length/2])
intersection()
{
cylinder(r=r, length);
cube([r, r, length]);
}
}
module rcube(size=[30, 20, 10], radius=[3, 2, 1], center=true)
{
hull() {
translate( center ? [0,0,0] : size/2 ) {
cube(size-2*radius+[2*radius[0],0,0],center=true);
cube(size-2*radius+[0,2*radius[1],0],center=true);
cube(size-2*radius+[0,0,2*radius[2]],center=true);
for(x = [-0.5,0.5], y = [-0.5,0.5], z = [-0.5,0.5])
translate([x * ( size[0] - 2*radius[0]),
y * ( size[1] - 2*radius[1]),
z * ( size[2] - 2*radius[2])])
scale([radius[0], radius[1], radius[2]])
if (quality == "high") sphere(1.0,$fn=4*4*2); else sphere(1.0,$fn=4);
}
}
}
module hole(diameter, depth)
{
$fn = 36;
cylinder(r=diameter/2, h=depth);
}
module wall(width, height, WallThickness)
{
translate([-width/2,-WallThickness/2,-height]) cube([width, WallThickness, height]);
}
module prism(l, w, h)
{
polyhedron(
points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
);
}
module post(height, diameter, post_fillet_r, screw_hole_diameter, screw_hole_depth)
{
$fn = 36;
difference() {
union() {
cylinder(r=diameter/2, h=height);
difference() {
cylinder(r=diameter/2 + post_fillet_r, h=post_fillet_r);
translate([0,0,post_fillet_r]) torus(diameter/2, post_fillet_r*1.1);
}
}
if (screw_hole_diameter>0)
{
translate([0,0,height-screw_hole_depth])
hole(screw_hole_diameter, screw_hole_depth);
}
}
}
module screwPost(ZDepth, PostDiameter, ScrewDiameter, ScrewHoleDepth, FilletR)
{
if (PostDiameter>0.0)
post(ZDepth, PostDiameter, FilletR, ScrewDiameter, ScrewHoleDepth);
}
module outerBox(SkinWidth, XWidth, YHeight, ZDepth, CornerRadius)
{
translate([-SkinWidth, -SkinWidth, 0]) roundedCube(XWidth+SkinWidth*2, YHeight+SkinWidth*2, ZDepth, CornerRadius);
}
module box(SkinWidth, XWidth, YHeight, ZDepth, CornerRadius)
{
// main shell
difference() {
outerBox(SkinWidth, XWidth, YHeight, ZDepth, CornerRadius);
//rcube(size=[XWidth+SkinWidth*2, YHeight+SkinWidth*2, ZDepth+SkinWidth*2], radius=[2, 2, 2], center=false);
if (SkinWidth>0)
roundedCube(XWidth, YHeight, ZDepth, CornerRadius);
//rcube(size=[XWidth, YHeight, ZDepth], radius=[2, 2, 2], center=false);
}
}

View File

@ -0,0 +1,18 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
// single button
module button()
{
// front part of the button
translate([-ButtonXWidth/2, -ButtonYHeight/2, 0])
roundedCube(ButtonXWidth, ButtonYHeight, ButonZDepth, ButtonCorners);
// slightly larger frame around the buttons rear, to keep the button from falling through the panel
translate([-(ButtonXWidth+ButtonLedgeWidth)/2, -(ButtonYHeight+ButtonLedgeWidth)/2, 0])
roundedCube(ButtonXWidth+ButtonLedgeWidth, ButtonYHeight+ButtonLedgeWidth, SKIN, ButtonCorners);
// connector for the button's peg
rotate([0,180,0]) screwPost(ButtonPegDepth, ButtonPegDiameter+2, ButtonPegDiameter, ButtonPegDepth, 1);
}

200
scad/components/front.scad Normal file
View File

@ -0,0 +1,200 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
// front panel hole for a rectangular button
module buttonCutout()
{
// add 1mm spacing, so the button moves freely (results in 0.5mm clearance on each side)
buttonXWidth = ButtonXWidth+0.5;
buttonYHeight = ButtonYHeight+0.5;
translate([-buttonXWidth/2, -buttonYHeight/2, 0])
roundedCube(buttonXWidth, buttonYHeight, SKIN, ButtonCorners);
}
// test / unused
module buttonFrame()
{
XWidth = ButtonXWidth+6;
YHeight = ButtonYHeight+6;
difference()
{
translate([-XWidth/2, -YHeight/2, 0])
roundedCube(XWidth, YHeight, SKIN, ButtonCorners);
buttonCutout();
}
}
// various holes for the front panel
module panelCutouts()
{
// LCD display
translate([BoxX_Width-DisplayXDistance, BoxY_Height-DisplayYDistance, 0])
{
translate([-DisplayWidth, -DisplayHeight, 0])
roundedCube(DisplayWidth, DisplayHeight, SKIN*2, DisplayCornerRadius);
}
// SD Slot
translate([BoxX_Width-SDSlotXDistance, SDSlotYDistance, 0])
{
translate([-SDSlotWidth, 0, 0])
roundedCube(SDSlotWidth, SDSlotHeight, SKIN, SDSlotCorners);
}
// LEDs
translate([BoxX_Width-LedXOfs, LedYOfs, 0]) hole(LedDiameter, SKIN);
if (LedCount>1)
translate([BoxX_Width-LedXOfs, LedYOfs-LedYDistance, 0]) hole(LedDiameter, SKIN);
// buttons
for (x = [0 : 1: 0])
{
for (y = [0 : 1: 0])
{
translate([ButtonXOfs+ButtonXWidth/2+(ButtonXSpacing)*x,
BoxY_Height-ButtonYHeight/2-ButtonYOfs-(ButtonYSpacing)*y, 0])
buttonCutout();
}
}
for (x = [1 : 1: 1])
{
for (y = [0 : 1: 2])
{
translate([ButtonXOfs+ButtonXWidth/2+(ButtonXSpacing)*x,
BoxY_Height-ButtonYHeight/2-ButtonYOfs-(ButtonYSpacing)*y, 0])
buttonCutout();
}
}
}
// pegs to hold the display
module displayPegs()
{
translate([BoxX_Width-DisplayXDistance, BoxY_Height-DisplayYDistance-DisplayHeight/2+DisplayPegYDistance/2-DisplayPegYOffset, SKIN])
{
translate([-DisplayWidth/2+DisplayPegXDistance/2, 0, 0])
screwPost(DisplayPegHeight, DisplayPegDiameter, 0, 0, 0);
translate([-DisplayWidth/2+DisplayPegXDistance/2, -DisplayPegYDistance,0])
screwPost(DisplayPegHeight, DisplayPegDiameter, 0, 0, 0);
translate([-DisplayWidth/2-DisplayPegXDistance/2, 0,0])
screwPost(DisplayPegHeight, DisplayPegDiameter, 0, 0, 0);
translate([-DisplayWidth/2-DisplayPegXDistance/2, -DisplayPegYDistance,0])
screwPost(DisplayPegHeight, DisplayPegDiameter, 0, 0, 0);
}
}
// screw posts and supports of the button panel
module buttonPanelSupports()
{
XOfs = ButtonXOfs+ButtonXWidth/2+ButtonRaster*3/2;
YOfs = BoxY_Height-ButtonYHeight/2-ButtonYOfs;
for (x = [-1 : 1: -1])
for (y = [0 : 2: 2])
{
echo("Button Panel mount (x/y):",ButtonXSpacing*x, ButtonYSpacing*y);
translate([XOfs+ButtonXSpacing*x, YOfs-ButtonYSpacing*y, SKIN])
screwPost(ButtonScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ButtonScrewPostHeight, 0.5);
}
for (x = [2 : 1: 2])
for (y = [0 : 2: 2])
{
echo("Button Panel mount (x/y):",ButtonXSpacing*x, ButtonYSpacing*y);
translate([XOfs+ButtonXSpacing*x, YOfs-ButtonYSpacing*y, SKIN])
screwPost(ButtonScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ButtonScrewPostHeight, 0.5);
}
}
module baseFrontPanel()
{
roundedCube(BoxX_Width-2*FrontPanelGap, BoxY_Height-FrontPanelGap, SKIN, Box_Corner_Radius);
}
module displayFrame()
{
// LCD display
translate([BoxX_Width-DisplayXDistance, BoxY_Height-DisplayYDistance, 0])
{
translate([-DisplayWidth-1, -DisplayHeight-1, SKIN])
roundedCube(DisplayWidth+2, DisplayHeight+2, DisplayFrameZHeight, DisplayCornerRadius);
}
}
// front panel
module makeFront()
{
translate([FrontPanelGap, 0, FrontPanelZOffset])
{
displayPegs();
difference()
{
union()
{
baseFrontPanel();
displayFrame();
}
panelCutouts();
}
// screw posts for the button panel
buttonPanelSupports();
difference()
{
translate([Box_Corner_Radius, 0, SKIN]) cube([BoxX_Width-Box_Corner_Radius*2, SKIN, FrontPanelZLedge]);
// hole
translate([FrontGapX/2, -SKIN , FrontPanelZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
// hole
translate([BoxX_Width-FrontGapX/2, -SKIN, FrontPanelZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
}
// LED sockets
translate([BoxX_Width-LedXOfs, LedYOfs, SKIN])
screwPost(LedSocketHeight, LedDiameter+2, LedDiameter, LedSocketHeight, 0);
if (LedCount>1)
translate([BoxX_Width-LedXOfs, LedYOfs-LedYDistance, SKIN])
screwPost(LedSocketHeight, LedDiameter+2, LedDiameter, LedSocketHeight, 0);
// support triangles
SupportWidth = FrontPanelZLedge;
// left
translate([Box_Corner_Radius, SKIN, SupportWidth+SKIN]) rotate([270, 0, 0]) prism(SKIN, SupportWidth, SupportWidth);
// right
translate([BoxX_Width-Box_Corner_Radius-SKIN, SKIN, SupportWidth+SKIN]) rotate([270, 0, 0]) prism(SKIN, SupportWidth, SupportWidth);
// screw posts
translate([FrontGapX/2, SKIN , FrontPanelZLedge/2])
{
rotate([270, 0, 0]) screwPost(ScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ScrewPostHeight, 0);
translate([-ScrewPostDiameter/2, 0, -FrontPanelZLedge/2+SKIN]) cube([ScrewPostHeight, ScrewPostDiameter, FrontPanelZLedge/3-SKIN]);
}
translate([BoxX_Width-FrontGapX/2, SKIN, FrontPanelZLedge/2])
{
rotate([270, 0, 0]) screwPost(ScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ScrewPostHeight, 0);
translate([-ScrewPostDiameter/2, 0, -FrontPanelZLedge/2+SKIN]) cube([ScrewPostHeight, ScrewPostDiameter, FrontPanelZLedge/3-SKIN]);
}
}
// front screw posts for FloppyEmu PCB
PcbFrontMountHeight = PcbYOfs-SKIN;
translate([BoxX_Width/2-PcbXWidth/2+PcbScrewDistance+PcbXOfs, SKIN , PcbZOfs+PcbScrewDistance])
{
rotate([270, 0, 0]) screwPost(PcbFrontMountHeight, PcbScrewPostDiameter, PcbScrewDiameter, PcbFrontMountHeight, 0);
translate([-PcbScrewPostDiameter/2,0,-PcbScrewPostDiameter/2]) cube([PcbScrewPostDiameter, PcbFrontMountHeight, PcbScrewPostDiameter/4]);
}
translate([BoxX_Width/2+PcbXWidth/2-PcbScrewDistance+PcbXOfs, SKIN, PcbZOfs+PcbScrewDistance])
{
rotate([270, 0, 0]) screwPost(PcbFrontMountHeight, PcbScrewPostDiameter, PcbScrewDiameter, PcbFrontMountHeight, 0);
translate([-PcbScrewPostDiameter/2,0,-PcbScrewPostDiameter/2]) cube([PcbScrewPostDiameter, PcbFrontMountHeight, PcbScrewPostDiameter/4]);
}
}

200
scad/components/main.scad Normal file
View File

@ -0,0 +1,200 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
// Radius of the corners
Box_Corner_Radius = 3.0*ScalingFactor; // [0: 10]
// Box skin width
SKIN = 1.0; // [1: 0.1: 5]
/* [Hidden] */
// Width (X) of the box
BoxX_Width = 155*ScalingFactor; // [60: 145]
// Height (Y) of the box
BoxY_Height = 90*ScalingFactor; // [10: 100]
// Depth (Z) of the box
BoxZ_Depth = 210*ScalingFactor; // [10: 200]
// Width of the ventilation cut
VentilationWidth = 4*ScalingFactor;
VentilationYHeight = 30*ScalingFactor;
VentilationXLength = 15*ScalingFactor;
// Distance of the first ventilation cut from the rear
VentilationZOffset = 17*ScalingFactor;
// Distance between the ventilation cuts
VentilationZDistance = 9.2*ScalingFactor;
// Number of ventilation cuts
VentilationCount = 9;
// Top grooves
TopGrooveXWidth = 110*ScalingFactor;
TopGrooveZLength = 80*ScalingFactor;
TopGrooveYDepth = 2;//*ScalingFactor;
TopGrooveCornerRadius = 6*ScalingFactor;
// Rear wall
RearWallGap = 1.5;
RearWallCableGapHeight = 3;
RearWallCableGapWidth = 27+3; //26mm cable width
RearWallCableGapXOffset = 10+2*ScalingFactor;
RearWallZLedge = 17;
RearWallZOffset = 2.5;
// Strain Relief
CableStrainReliefYOffset = BoxY_Height-20; // distance from the top of the box
// Front panel
FrontPanelGap = 0.5;
FrontPanelZLedge = 10;
FrontPanelZOffset = 2;
// Distance of the gap at the front (from the left/right edge)
FrontGapX = 21;
FrontGapWidth = 0.8;
FrontGapY = FrontPanelZOffset+5;
// Screws
ScrewDiameter = 3;
ScrewPostDiameter = ScrewDiameter+2;
ScrewPostHeight = 5;
ScrewPostFillet = 2;
// Display
DisplayWidth = 30+1+1; // active area: 29.42
DisplayHeight = 15+1+2; // active area: 14.7
DisplayXDistance = 15*ScalingFactor; // distance from the left of the panel
DisplayYDistance = 3.5+9*ScalingFactor; // distance from the top of the panel
DisplayCornerRadius = 2;
DisplayPegXDistance = 31-0.2;
DisplayPegYDistance = 28.5;
DisplayPegYOffset = 2.25;//-4.5; // 7.35-2=5.35 from the top, 3.25 The display mounting ports are not centered, but have an offset (shifted towards the bottom).
// frame around the display opening
DisplayFrameZHeight = 0.5;
// Pegs to hold the display
DisplayPegHeight = 4+1;
DisplayPegDiameter = 3; // 3.5
// SDSlot
SDSlotWidth = 12.5; // 12
SDSlotHeight = 3;
SDSlotCorners = 1;
SDSlotXDistance = BoxX_Width/2-SDSlotWidth/2; // distance from the left of the panel
SDSlotYDistance = 10; // distance from the bottom of the panel to the bottom of the SD slot
// Square Buttons
ButtonYHeight = (ScalingFactor<1) ? 8.5 : 10;
ButtonXWidth = (ScalingFactor<1) ? 8.5 : 10;
ButonZDepth = SKIN*2+1.5;
ButtonCorners = 1;
ButtonLedgeWidth = 2-0.5;
ButtonPegDiameter = 3.5+0.2-0.1;
ButtonPegDepth = 2.5;
ButtonXOfs = 15*ScalingFactor; // distance from the right edge
ButtonYOfs = 9*ScalingFactor;//9*ScalingFactor; // distance from the top
ButtonRaster = 2.54; // 0.01"
ButtonXSpacing = ButtonRaster*5; // multiple of 2.54mm => allow micro switches to be soldered on prototype raster PCBs
ButtonYSpacing = ButtonRaster*5; // multiple of 2.54mm => allow micro switches to be soldered on prototype raster PCBs
ButtonScrewPostHeight = 9-0.5;
// LEDs
LedDiameter = (ScalingFactor<1) ? 3.4-0.1 : 5; // 3.4
LedSocketHeight = 1.5;
LedYDistance = (ScalingFactor<1) ? LedDiameter+3 : LedDiameter+3.5; // distance between the two LEDs
LedXOfs = (ScalingFactor<1) ? 22 : 20+LedDiameter/2; // distance from the left edge
LedYOfs = (ScalingFactor<1) ? 16 : 20;
// FloppyEmu PCB
PcbXWidth = 45-1;
PcbYHeight = 2;
PcbZDepth = 100.0;
PcbXOfs = -0.75+0.5; // from the center. SD Slot on FloppyEmu is not quite centered
PcbYOfs = SDSlotYDistance-PcbYHeight+1;
PcbZOfs = FrontPanelZOffset+SKIN+0.5;
PcbScrewDiameter = 3;
PcbScrewPostDiameter = PcbScrewDiameter+3;
PcbScrewDistance = 2.5; // distance from the PCB edges
include <baseLib.scad>;
include <top_and_bottom.scad>;
include <pcb.scad>;
include <buttons.scad>;
include <rear.scad>;
include <front.scad>;
module main()
{
if (part == "test")
{
intersection()
{
makeTop();
translate([-10,BoxY_Height-22,BoxZ_Depth-32]) cube([40, 40, 32]);
}
}
else
if (part == "button")
{
for (x = [0,1])
for (y = [0,1])
translate([x*ButtonXSpacing, y*ButtonYSpacing, -ButonZDepth]) button();
translate([-15, 20, 0]) rotate([0,0,90]) makeCableStrainRelief();
translate([30, -15, 0]) makeRearPcbFeet();
}
else
if (part == "rear")
{
makeRear();
}
else
if (part == "front")
{
makeFront();
}
else
if (part == "top") {
makeTop();
}
else
if (part == "topBottom") {
makeTop();
translate([0, -ComponentSeparation, 0 ]) makeBottom();
}
else
if (part == "bottom") {
makeBottom();
}
else
if (part == "all") {
makeTop();
translate([0, -ComponentSeparation, 0 ]) makeBottom();
translate([0, 0, ComponentSeparation ]) makeRear();
translate([0, 0, -ComponentSeparation ]) makeFront();
}
else
if ((part == "noFront")||(part == "noRear")||(part=="noBottom")||(part=="frontBottom"))
{
if (part != "frontBottom") makeTop();
if (part != "noBottom") makeBottom();
if ((part != "noRear")&&(part != "frontBottom")) makeRear();
if (part != "noFront") makeFront();
}
else
if (part == "prototype") {
boxScrewPosts();
} else {
// nothing!
}
if ((showPcb == "yes")&&(part != "button")) makePcb();
}
main();

44
scad/components/pcb.scad Normal file
View File

@ -0,0 +1,44 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
// floppy emu PCB
module makePcb()
{
translate([BoxX_Width/2 - PcbXWidth/2+PcbXOfs, PcbYOfs, PcbZOfs])
{
difference()
{
// PCB
cube([PcbXWidth, PcbYHeight, PcbZDepth]);
// front holes
translate([PcbScrewDistance,0,PcbScrewDistance]) rotate([270, 0, 0]) hole(PcbScrewDiameter, PcbYHeight);
translate([PcbXWidth-PcbScrewDistance,0,PcbScrewDistance]) rotate([270, 0, 0]) hole(PcbScrewDiameter, PcbYHeight);
// rear holes
translate([PcbScrewDistance,0,PcbZDepth-PcbScrewDistance]) rotate([270, 0, 0]) hole(PcbScrewDiameter, PcbYHeight);
translate([PcbXWidth-PcbScrewDistance,0,PcbZDepth-PcbScrewDistance]) rotate([270, 0, 0]) hole(PcbScrewDiameter, PcbYHeight);
}
}
}
module makeRearPcbFeet(center)
{
//translate([BoxX_Width/2 - PcbXWidth/2+PcbXOfs, PcbYOfs, PcbZDepth+PcbZOfs])
rotate([90,0,90])
{
difference()
{
translate([-PcbScrewDiameter/2, -SKIN, -PcbScrewDistance-PcbScrewDiameter])
cube([PcbXWidth+PcbScrewDiameter, SKIN, PcbScrewDiameter*2]);
// holes
translate([PcbScrewDistance,-SKIN,-PcbScrewDistance]) rotate([270, 0, 0])
hole(PcbScrewDiameter, PcbYHeight);
translate([PcbXWidth-PcbScrewDistance,-SKIN,-PcbScrewDistance]) rotate([270, 0, 0])
hole(PcbScrewDiameter, PcbYHeight);
}
FeetYHeight = PcbYOfs-SKIN;
translate([PcbScrewDistance,-SKIN,-PcbScrewDistance]) rotate([90, 0, 0])
screwPost(FeetYHeight, PcbScrewDiameter*2, PcbScrewDiameter, FeetYHeight, 0);
translate([PcbXWidth-PcbScrewDistance,-SKIN,-PcbScrewDistance]) rotate([90, 0, 0])
screwPost(FeetYHeight, PcbScrewDiameter*2, PcbScrewDiameter, FeetYHeight, 0);
}
}

91
scad/components/rear.scad Normal file
View File

@ -0,0 +1,91 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
// rear panel
module makeRear()
{
Width = BoxX_Width-2*RearWallGap;
difference()
{
translate([RearWallGap, 0, BoxZ_Depth-RearWallZOffset-RearWallZLedge])
rotate([90, 0, 90])
{
difference()
{
roundedCube(BoxY_Height, RearWallZLedge, Width, Box_Corner_Radius);
translate([SKIN, -SKIN, 0]) roundedCube(BoxY_Height, RearWallZLedge, Width, Box_Corner_Radius);
translate([BoxY_Height-RearWallGap-RearWallCableGapHeight,RearWallZLedge-SKIN*2,0])
cube([RearWallCableGapHeight+10, SKIN*2, Width]);
}
}
// hole
translate([FrontGapX/2, -SKIN , BoxZ_Depth-RearWallZOffset-RearWallZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
// hole
translate([BoxX_Width-FrontGapX/2, -SKIN , BoxZ_Depth-RearWallZOffset-RearWallZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
}
// long edge, top of rear wall
translate([RearWallGap, BoxY_Height-RearWallGap-RearWallCableGapHeight-5, BoxZ_Depth-RearWallZOffset-SKIN])
roundedCube(BoxX_Width-RearWallCableGapWidth-RearWallCableGapXOffset, RearWallCableGapHeight+5, SKIN, Box_Corner_Radius);
// short edge, top of rear wall
translate([BoxX_Width-RearWallGap-RearWallCableGapXOffset, BoxY_Height-RearWallGap-RearWallCableGapHeight-5, BoxZ_Depth-RearWallZOffset-SKIN])
roundedCube(RearWallCableGapXOffset, RearWallCableGapHeight+5, SKIN, Box_Corner_Radius);
// screw posts
translate([FrontGapX/2, SKIN , BoxZ_Depth-RearWallZOffset-RearWallZLedge/2]) rotate([270, 0, 0])
screwPost(ScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ScrewPostHeight, ScrewPostFillet);
translate([BoxX_Width-FrontGapX/2, SKIN , BoxZ_Depth-RearWallZOffset-RearWallZLedge/2]) rotate([270, 0, 0])
screwPost(ScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ScrewPostHeight, ScrewPostFillet);
// cable strain relief
translate([BoxX_Width-RearWallGap-RearWallCableGapXOffset+ScrewPostDiameter, BoxY_Height-CableStrainReliefYOffset, BoxZ_Depth-RearWallZOffset-SKIN])
rotate([180,0,0]) screwPost(ScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ScrewPostHeight, ScrewPostFillet);
translate([BoxX_Width-RearWallGap-RearWallCableGapXOffset-RearWallCableGapWidth, BoxY_Height-CableStrainReliefYOffset, BoxZ_Depth-RearWallZOffset-SKIN])
rotate([180,0,0]) screwPost(ScrewPostHeight, ScrewPostDiameter, ScrewDiameter, ScrewPostHeight, ScrewPostFillet);
StrainReliefHeight=2;
CableThickness = 0;
translate([BoxX_Width-RearWallGap-RearWallCableGapXOffset-RearWallCableGapWidth+ScrewPostDiameter/2, BoxY_Height-CableStrainReliefYOffset-StrainReliefHeight/2, BoxZ_Depth-RearWallZOffset-SKIN-ScrewPostHeight+CableThickness])
cube([RearWallCableGapWidth, StrainReliefHeight, ScrewPostHeight-CableThickness]); // 0.5mm to allow a bit space for the cable
// support triangles for stability
SupportWidth = RearWallZLedge-SKIN*2;
// left
translate([RearWallGap+Box_Corner_Radius, SKIN, BoxZ_Depth-RearWallZOffset-SupportWidth-SKIN])
rotate([270, 180, 0]) prism(SKIN, SupportWidth, SupportWidth);
// right
translate([BoxX_Width-Box_Corner_Radius-SKIN, SKIN, BoxZ_Depth-RearWallZOffset-SupportWidth-SKIN])
rotate([270, 180, 0]) prism(SKIN, SupportWidth, SupportWidth);
// center
translate([(BoxX_Width-Box_Corner_Radius-SKIN)/2, SKIN, BoxZ_Depth-RearWallZOffset-SupportWidth-SKIN])
rotate([270, 180, 0]) prism(SKIN, SupportWidth, SupportWidth);
}
module makeCableStrainRelief()
{
StrainReliefHeight=4+SKIN;
difference()
{
union()
{
// cable strain relief
translate([ScrewPostDiameter, 0, 0])
rotate([180,0,0]) screwPost(StrainReliefHeight, ScrewPostDiameter, ScrewDiameter, StrainReliefHeight, 0);
translate([-RearWallCableGapWidth, 0, 0])
rotate([180,0,0]) screwPost(StrainReliefHeight, ScrewPostDiameter, ScrewDiameter, StrainReliefHeight, 0);
translate([-RearWallCableGapWidth+ScrewPostDiameter/3, -(StrainReliefHeight-SKIN)/2, -(StrainReliefHeight-SKIN)])
cube([RearWallCableGapWidth+1, (StrainReliefHeight-SKIN), StrainReliefHeight-SKIN]); // 0.5mm to allow a bit space for the cable
translate([-RearWallCableGapWidth,-ScrewPostDiameter/2,-SKIN])
cube([RearWallCableGapWidth+ScrewPostDiameter, ScrewPostDiameter, SKIN]);
}
translate([ScrewPostDiameter,0,-SKIN]) hole(ScrewDiameter, SKIN);
translate([-RearWallCableGapWidth,0,-SKIN]) hole(ScrewDiameter, SKIN);
}
}

View File

@ -0,0 +1,312 @@
// Copyright 2022 Thorsten Brehm
// brehmt (at) gmail dot com
module imprint(x,y,z)
{
Font = "Liberation Sans:style=Bold";
FontSize = 3;
translate([x,y,z])
rotate([270,0,0])
{
linear_extrude(height = 0.4) { text(IMPRINT, font = Font, size = FontSize, halign="center", valign="bottom"); }
}
}
// little mounting point, so the base plate does not drop when glueing to the top shell
module makeGlueHelper(Width)
{
SupportAngle = 35;
intersection()
{
union()
{
translate([-20, 0, 0])
rotate([0, 0, SupportAngle])
translate([-20,-25,-Width/2])
cube([40, 50, Width]);
}
translate([0,0,-Width/2]) cube([40,50,Width]);
}
}
// little mounting points to help when glueing the base to the top shell
module makeGlueMountingPoints()
{
SupportWidth = 5; // 10mm
//SupportXOffset = -36.9;
SupportXOffset1 = -28;//34.9;
//SupportXOffset2 = SupportXOffset1+32.1;
SupportXOffset2 = 32.1;
// support for bottom curved edges
SupportYOffset = 0;
FrontZ = FrontPanelZLedge+FrontPanelZOffset+SKIN*5; // front position
RearZ = BoxZ_Depth-RearWallZLedge-RearWallZOffset-5*SKIN; // rear position
intersection()
{
union()
{
for (z=[FrontZ, RearZ, (FrontZ+RearZ)/2])
{
// right
translate([0, SupportYOffset, z]) makeGlueHelper(SupportWidth);
// left
translate([BoxX_Width, SupportYOffset, z]) rotate([0, 180, 0]) makeGlueHelper(SupportWidth);
}
}
// cut away anything which is outside the shell
outerBox(SKIN, BoxX_Width, BoxY_Height, BoxZ_Depth, Box_Corner_Radius);
}
}
module makeTopStiffeners()
{
SupportWidth = 15;
// front right
translate([0, BoxY_Height-SupportWidth, FrontPanelZOffset+SKIN*2+15]) rotate([0,90,0]) prism(SKIN, SupportWidth, SupportWidth);
// front left
translate([BoxX_Width, BoxY_Height-SupportWidth, FrontPanelZOffset+SKIN+15]) rotate([0,270,0]) prism(SKIN, SupportWidth, 10);
// center right
translate([0, BoxY_Height-SupportWidth, BoxZ_Depth/2]) rotate([0,90,0]) prism(SKIN, SupportWidth, SupportWidth);
// center left
translate([BoxX_Width, BoxY_Height-SupportWidth, BoxZ_Depth/2-SKIN]) rotate([0,270,0]) prism(SKIN, SupportWidth, SupportWidth);
// rear right
translate([0, BoxY_Height-SupportWidth, BoxZ_Depth-RearWallZOffset-SKIN-3-2]) rotate([0,90,0]) prism(SKIN, SupportWidth, SupportWidth);
// rear left
translate([BoxX_Width, BoxY_Height-SupportWidth, BoxZ_Depth-RearWallZOffset-3-SKIN*2-2]) rotate([0,270,0]) prism(SKIN, SupportWidth, SupportWidth);
}
module roundedEdge()
{
translate([-SKIN, 0, 30]) rotate([270, 0, 0]) roundedCube(2, 30, SKIN, 1);
}
module roundCorner()
{
$fn=24;
Radius = TopGrooveCornerRadius/2;
translate([0,1,0]) rotate([270, 0, 0])
translate([-Radius-TopGrooveYDepth, -Radius-TopGrooveYDepth, 0])
intersection()
{
torus(Radius, TopGrooveYDepth);
cube([Radius*2, Radius*2, TopGrooveYDepth]);
}
}
module makeRoundGapEdges()
{
// front left
translate([FrontGapX-FrontGapWidth/2-1, -SKIN, 0]) roundedEdge();
translate([FrontGapX+FrontGapWidth/2+1, -SKIN, 0]) roundedEdge();
// front right
translate([BoxX_Width-FrontGapX-FrontGapWidth/2-1, -SKIN, 0]) roundedEdge();
translate([BoxX_Width-FrontGapX+FrontGapWidth/2+1, -SKIN, 0]) roundedEdge();
// rear left
translate([FrontGapX-FrontGapWidth/2-1, -SKIN, BoxZ_Depth-30]) roundedEdge();
// rear right
translate([BoxX_Width-FrontGapX+FrontGapWidth/2+1, -SKIN, BoxZ_Depth-30]) roundedEdge();
}
module makeGaps()
{
// front gaps
translate([FrontGapX-FrontGapWidth/2-1, -SKIN, 0]) cube([FrontGapWidth+2, SKIN*2, FrontGapY]);
translate([BoxX_Width-FrontGapX-FrontGapWidth/2-1, -SKIN, 0]) cube([FrontGapWidth+2, SKIN*2, FrontGapY]);
// rear gap
translate([FrontGapX-FrontGapWidth/2-1, -SKIN, BoxZ_Depth-10]) cube([BoxX_Width-2*FrontGapX+FrontGapWidth+2, SKIN*2, 10]);
}
module ventilationCut()
{
translate([-SKIN, BoxY_Height-VentilationYHeight,BoxZ_Depth-VentilationZOffset]) rotate([0, 90, 0])
roundedCube(VentilationWidth, VentilationYHeight, SKIN, VentilationWidth/2);
translate([BoxX_Width, BoxY_Height-VentilationYHeight,BoxZ_Depth-VentilationZOffset]) rotate([0, 90, 0])
roundedCube(VentilationWidth, VentilationYHeight, SKIN, VentilationWidth/2);
translate([-SKIN-VentilationYHeight+VentilationXLength, BoxY_Height+SKIN,BoxZ_Depth-VentilationZOffset]) rotate([90, 90, 0])
roundedCube(VentilationWidth, VentilationYHeight, SKIN+5, VentilationWidth/2);
translate([BoxX_Width-VentilationXLength, BoxY_Height+SKIN,BoxZ_Depth-VentilationZOffset]) rotate([90, 90, 0])
roundedCube(VentilationWidth, VentilationYHeight, SKIN+5, VentilationWidth/2);
}
module makeVentilation()
{
for (z = [0 : 1: VentilationCount-1])
{
translate([0, 0, -z*VentilationZDistance]) ventilationCut();
}
}
module makeScrewHoles()
{
// front hole
translate([FrontGapX/2, -SKIN, FrontPanelZOffset+FrontPanelZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
// front hole
translate([BoxX_Width-FrontGapX/2, -SKIN, FrontPanelZOffset+FrontPanelZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
// rear hole
translate([FrontGapX/2, -SKIN , BoxZ_Depth-RearWallZOffset-RearWallZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
// rear hole
translate([BoxX_Width-FrontGapX/2, -SKIN, BoxZ_Depth-RearWallZOffset-RearWallZLedge/2]) rotate([270, 0, 0])
hole(ScrewDiameter, 10);
// rear PCB holes
translate([BoxX_Width/2-PcbXWidth/2, 0, PcbZOfs])
{
translate([PcbScrewDistance, -SKIN,PcbZDepth-PcbScrewDistance]) rotate([270, 0, 0]) hole(PcbScrewDiameter, SKIN);
translate([PcbXWidth-PcbScrewDistance, -SKIN,PcbZDepth-PcbScrewDistance]) rotate([270, 0, 0]) hole(PcbScrewDiameter, SKIN);
}
}
GrooveSupportZOffset = (BoxZ_Depth-2*TopGrooveZLength)/3;
GrooveXOfs = BoxX_Width/2-(TopGrooveXWidth+4)/2;
module makeTopGroovesSupport()
{
translate([GrooveXOfs, BoxY_Height-TopGrooveYDepth, GrooveSupportZOffset+TopGrooveZLength+2]) rotate([270, 0, 0])
roundedCube(TopGrooveXWidth+4, TopGrooveZLength+4, TopGrooveYDepth, TopGrooveCornerRadius);
translate([GrooveXOfs, BoxY_Height-TopGrooveYDepth, GrooveSupportZOffset*2+TopGrooveZLength*2+2]) rotate([270, 0, 0])
roundedCube(TopGrooveXWidth+4, TopGrooveZLength+4, TopGrooveYDepth, TopGrooveCornerRadius);
}
module makeTopGroovesEdges()
{
for (z=[GrooveSupportZOffset,2*GrooveSupportZOffset+TopGrooveZLength])
translate([GrooveXOfs+2, BoxY_Height-TopGrooveYDepth+SKIN, z])
{
// right edge
translate([0, 0, 4+TopGrooveZLength/2-5])
cylinderLedge(TopGrooveYDepth, TopGrooveZLength);
// left edge
translate([TopGrooveXWidth, 0, 4+TopGrooveZLength/2-5])
rotate([0, 180, 0]) cylinderLedge(TopGrooveYDepth, TopGrooveZLength);
// front edge
translate([TopGrooveXWidth/2, 0, 0])
rotate([0, 270, 0]) cylinderLedge(TopGrooveYDepth, TopGrooveXWidth);
// rear edge
translate([TopGrooveXWidth/2, 0, TopGrooveZLength])
rotate([0, 90, 0]) cylinderLedge(TopGrooveYDepth, TopGrooveXWidth);
// rear right corner
translate([TopGrooveXWidth, -1, 0]) roundCorner();
// rear left corner
translate([0, -1, 0]) rotate([0, 90, 0]) roundCorner();
// front right corner
translate([TopGrooveXWidth, -1, TopGrooveZLength]) rotate([0, 270, 0]) roundCorner();
// front left corner
translate([0, -1, TopGrooveZLength]) rotate([0, 180, 0]) roundCorner();
}
}
module makeTopGrooves()
{
GrooveZOffset = (BoxZ_Depth-2*TopGrooveZLength)/3;
translate([BoxX_Width/2-TopGrooveXWidth/2, BoxY_Height-TopGrooveYDepth+SKIN, GrooveZOffset+TopGrooveZLength]) rotate([270, 0, 0])
roundedCube(TopGrooveXWidth, TopGrooveZLength, TopGrooveYDepth, TopGrooveCornerRadius);
translate([BoxX_Width/2-TopGrooveXWidth/2, BoxY_Height-TopGrooveYDepth+SKIN, GrooveZOffset*2+TopGrooveZLength*2]) rotate([270, 0, 0])
roundedCube(TopGrooveXWidth, TopGrooveZLength, TopGrooveYDepth, TopGrooveCornerRadius);
}
// little supports to prevent the front and rear panels from bending into the case
module makeTopPanelSupports()
{
Distance = 10; // distance of the supports from the left/right edge of the box
SupportWidth = 3; // x,z size of the supports
SupportYHeight = 4; // y size of the supports (cube)
// front left
translate([BoxX_Width-5, BoxY_Height-SupportYHeight, FrontPanelZOffset+SKIN])
cube([SupportWidth, SupportYHeight, SupportWidth]);
// front right
translate([18, BoxY_Height-SupportYHeight, FrontPanelZOffset+SKIN])
cube([SupportWidth, SupportYHeight, SupportWidth]);
// front center
translate([BoxX_Width/2-4, BoxY_Height-SupportYHeight, FrontPanelZOffset+SKIN])
cube([SupportWidth, SupportYHeight, SupportWidth]);
// rear
translate([BoxX_Width-RearWallCableGapXOffset/2-SupportWidth,
BoxY_Height-SupportYHeight, BoxZ_Depth-RearWallZOffset-SKIN-SupportWidth])
cube([SupportWidth, SupportYHeight, SupportWidth]);
translate([Distance, BoxY_Height-SupportYHeight, BoxZ_Depth-RearWallZOffset-SKIN-SupportWidth])
cube([SupportWidth, SupportYHeight, SupportWidth]);
}
module makeThing()
{
union()
{
difference()
{
union()
{
box(SKIN, BoxX_Width, BoxY_Height, BoxZ_Depth, Box_Corner_Radius);
makeTopGroovesSupport();
makeGlueMountingPoints();
}
makeGaps();
makeVentilation();
makeTopGrooves();
makeScrewHoles();
if (prototype == "yes")
{
removePrototypeAreas();
}
}
makeRoundGapEdges();
makeTopGroovesEdges();
makeTopPanelSupports();
makeTopStiffeners();
}
}
module makeMask()
{
XOffs = 3.5*ScalingFactor;
translate([XOffs/2, -BoxY_Height, 0]) cube([BoxX_Width-XOffs, BoxY_Height+SKIN, BoxZ_Depth]);
}
module makeTop()
{
difference()
{
makeThing();
makeMask();
}
}
module makeBottom()
{
intersection()
{
makeThing();
makeMask();
}
imprint(BoxX_Width/2,0,BoxZ_Depth-RearWallZLedge-RearWallZOffset);
}

View File

@ -18,7 +18,7 @@ LEDs = "one"; // [one:One / Activity LED,two:Both / Activity and Power LEDs]
/* [Internals] */
// Base board imprint
IMPRINT = "MADE IN GERMANY"; // 20
IMPRINT = "MADE IN GERMANY"; // 30
// Distance of the components (when showing 'exploded' elements)
SEPARATION = 30; // [0: 1: 100]