working udp

This commit is contained in:
interfisch 2024-10-27 17:14:40 +01:00
commit b408409611
26 changed files with 189798 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View file

@ -0,0 +1,788 @@
/*******************************************************************************
TITLE:
Stable and waterproof OpenSCAD case by pbtec
DESCRIPTION:
highly scalable case for 3D printing. Try it out!
Optimized for Openscad Customizer. Activate it under view/customizer and play around ;-)
No Support needed to print
- for waterproof cases you can use silicone sealing cord with diameters from 1 to 3mm
- to use also without sealing cord. The groove and ridge gives the housing a high stability and tightness.
- Use of regular nuts or square nuts
- define outer vertical radius of corners
- echo output in console shows inner and outer size and more
- echo output shows the needed length of the screws
- use screws from m2 up to m5
- default are 4 screws at each corner. For large cases add addtional ones in the middle of both x and y sides if needed
- use several predefined wall mount holder, some with multiple mounting holes (up to 3)
Important!
- If you use standard nuts you need to pause the printer a certain level to insert the nuts
- If you need a stable and waterproof case please print with 100% infill
- I'm aware that sometimes, when using too big or too small parameters, there are some rendering issues.
To prevent such issues change only one parameter at once and check the result.
for waterproofness see https://blog.prusaprinters.org/watertight-3d-printing-part-2_53638/
AUTHOR:
pbtec / pb-tec.ch
use https://paypal.me/pbtec if you want to spend me a coold beer. Thanks in advance :-)
VERSION:
V KZZ DATE COMMENT
6.0 pb 31.07.21 First Version to share
*******************************************************************************/
/* [View settings] */
// Shows the Bottom of the case
ShowBottom = true;
// Shows the top of the case
ShowTop = true;
// Distance between top and bottom (if both are side by side displayed)
DistanceBetweenObjects = 10;
// Shows the housing assembled
ShowCaseAssembled = false;
/* [Control cuts (use only one at a time)] */
// To see the nuts inside (best view if not assembled showed)
SeeNutCut = false;
// To see the groove, ridge and Screw (best view if assembled showed)
SeeGrooveRidgeScrew = false;
/* [Case settings] */
// Length of the case
Caselength = 60;
// Width of the case
CaseWidth = 100;
// Height of the case
CaseHeight = 40;
// Splitt the Case height into bottom and top, check for the needed screws in echo output (console)
CutFromTop = 5.0;
// Thickness for the bottom and top wall (vertical walls needs to be calculated)
BottomTopThickness = 2.0;
// If this is bigger than the needed cylinder around the screw it will be ignored
CaseRadius = 12.0;
/* [Case Screw settings] */
//2=m2/2.5=m2.5/3=m3/4=m4/5=m5 // max m5, larger sizes do not fit
CountersinkScrew = 3.0; // [2:m2, 2.5: m2.5, 3: m3, 4: m4, 5: m5]
// Adds additional Screws on X axis (for large cases) --> Try it out
XAdditionalScrew = false; // can be true or false / Adds additional Screws on X axis (for large cases) --> Try it out
// Adds additional Screws on Y axis (for large cases) --> Try it out
YAdditionalScrew = false; // can be true or false / Adds additional Screws on Y axis (for large cases) --> Try it out
/* [Groove settings] */
// If using a SealingCord use the SealingCord diameter, otherwise x-times of your 3D Printer Nozzle (0.8/1.2/...) --> Ridge gets perfect for printing
GrooveWidth = 1.2; // [0.8:0.1:3]
// Not less than 1mm (for stability) and not more than 3mm --> Best 2mm
GrooveDepth = 2.0; // [1.0:0.1:3]
// Space between Groove and Ridge for a perfect fit, usualy 0.2 or 0.3 for FDM depending on your printer quality
Space = 0.3; // [0.0:0.1:0.4]
// Addtional vertical room for the pressed sealing Cord. For sealing cord 1.5mm -->0.5 // for 2mm -->0.8 // for 2.5 -->1.0 // If no sealing cord then set this parameter to 0.
AddGrooveDepthForSealing = 0.8; // [0.0:0.1:3]
// Range Inside groove/ridge. Usualy 2 times or more the printer nozzle. For best stability at least 0.8
InnerBorder = 0.8; // [0.8:0.1:4]
// Range Outside groove/ridge . Usualy 2 times or more the printer nozzle. For best stability at least 0.8
OuterBorder = 0.8; // [0.8:0.1:4]
/* [Nut general settings] */
// Size of material (plastic) above nut/square nut (3mm or more). The more, the more stable but need longer screw.
NutSink = 4.0;
/* [Standard nut settings] */
// Nut Settings / As there are (or I have) many different nuts dimensions, the size must be specified / Do not add separation space, only the real measurement // m2=1.5 // m2.5=1.9 // m3=2.4 // m4=3.2 // n5=3.8
NutHigh = 2.4;
// Distance between the paralell sides / Do not add separation space, only the real measurement // m2=3.8 // m2.5=4.9 // m3=5.4 // m4=6.9 // m5=7.9
NutDia = 5.4;
/* [Square Nut settings] */
// Select if you want to use square nuts instead of normal nuts
UseSquareNutInsteadOfNut = false;
// Select the high of the square nut / Do not add separation space, only the real measurement
SquareNutHigh = 1.9;
// Select the size of the square nut / Do not add separation space, only the real measurement
SquareNutSize = 5.4;
// Square nut insert from which side
EdgeSquareNutInsertFrom_X = true;
/* [Wall mount holder settings] */
// Select if you need a mount holder
EnableMountHolder = false;
// Chose your desired wall mount style
MountHolderStyle = 5; // [1:Style 1, 2: Style 2, 3: Style 3, 4 : Style 4, 5 : Style 5]
// Some styles (1-3) allow more than one hole
CountOfMountHolderHoles = 1; // [1:One hole centered, 2: Two holes, 3: Three holes]
MountHolderHoleDiameter = 5; // [1:0.1:10]
MountHolderThickness = 4.0; // [2:0.1:10]
/* [PCB/Device holder settings] */
// Activate customizable PCB/Device holder
ShowDeviceHolder = false;
// Hole in the cylinder for the screw // 2.9 Screw = 2mm hole
ScrewHoleDiameter = 2.6;
// The diamter of the screw cylinder
ScrewCylinderDiameter = 7;
// The height of the screw cylinders (also the deepness for the screw hole)
ScrewCylinderHeight = 8.0;
// Distance between the holders in X direction
DeviceHolder_X_Distance = 60;
// Distance between the holders in Y direction
DeviceHolder_y_Distance = 80;
// Move all holders in X direction
Offset_X = 0;
// Move all holders in Y direction
Offset_Y = -20;
/* [Wall Holes settings (for cable gland cut)] */
// Activate customizable holes for cable gland or similar
ShowSideWallHoles = false;
// Holes on X or Y side of the housing
SideWallHolesOn_X = false;
// Count of holes, if there is an additional screw on X or Y side the hole in the middle is not showed
CountOfSideWallHoles = 1; //[1:1:3]
// Diameter of the holes
SideWallHoleDiameter = 16.5; //[1:0.1:80]
// Add or decrease height position
SiedWallHoleOffset_Z = 0;
/* [Render quality settings] */
// Set to at least to 150 before render and save as .stl file, otherwise you can go down to 40 for quick 3D view
$fn = 60; // [20:1:300]
// ========================= C A L C U L A T E D S E T T I N G S (do not change!!!) ===================================
// Calculated Screw settings (do not change!!!)
ScrewHoleDia = CountersinkScrew+1;
ScrewHeadDia = CountersinkScrew*2;
ScrewCountersink = (CountersinkScrew+8)/14-0.5;
// Calculated settings for Ridge (do not change!!!)
RidgeHeight = GrooveDepth-Space;
RidgeWidth = GrooveWidth-Space;
// Calculated settings for case (do not change!!!)
SideWallThickness = InnerBorder+GrooveWidth+OuterBorder;
CaseRoundingRadius = ScrewHoleDia/2+InnerBorder+GrooveWidth+OuterBorder;
ScrewCornerPos = [Caselength/2-CaseRoundingRadius,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddXPos = [0,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddYPos = [Caselength/2-CaseRoundingRadius,0,0];
// Calculated settings for wall mount holder
MountHolderLenght = MountHolderHoleDiameter*3;
// if both objects showed
X_ObjectPosition = ((ShowBottom)&&(ShowTop)&&(!ShowCaseAssembled)) ? Caselength/2+DistanceBetweenObjects/2:0;
// If the case is assembled showed
Y_TopRotation = ShowCaseAssembled ? 180:0;
Z_TopHigh = ShowCaseAssembled ? CaseHeight:0;
ShowSizes(); // Show the calculated sizes
//===============================================================================
// M A I N
//===============================================================================
// --> Show the bottom of the case
translate([X_ObjectPosition,0,0]) rotate([0,0,0]) difference(){
union(){
BodyBottom();
// **** Add your bottom case additions here ****
//cylinder(h=20,d=15,center = true); // Example
//#translate([-18,0,18/2+2]) rotate([90,0,0]) cylinder(h=70,d=18,center=true); //battery mockup
translate([-6,0,20/2+0.1]) cube([2,CaseWidth-4,20],center=true); //battery divider
translate([-15,CaseWidth/2-5.5,20/2+0.1]) cube([16,7,20],center=true); //battery ends
translate([-15,-(CaseWidth/2-5.5),20/2+0.1]) cube([16,7,20],center=true); //battery ends
//#translate([10,20,18/2+3+17-3]) cube([26,35,18],center=true); //wemos mockupo
ButtonSides(4,-(15+2)*2);
ButtonSides(4,-(15+2)*1);
//ButtonSides(4,0);
//ButtonSides(4,(15+2)*1);
ButtonSides(4,(15+2)*2);
}
// **** Add your bottom case cuts here ****
//cylinder(h=15,d=20,center = true); // Example
ButtonCut(4,-(15+2)*2);
ButtonCut(4,-(15+2)*1);
//ButtonCut(4,0);
//ButtonCut(4,(15+2)*1);
ButtonCut(4,(15+2)*2);
translate([20,0,10]) rotate([0,90,0]) cylinder(h=20,d=6); //on off switch
translate([27,6.5,10]) cube([2,2,2],center=true); //on off switch notch
}
// --> Show the top of the case
translate([-X_ObjectPosition,0,Z_TopHigh+0.03]) rotate([0,Y_TopRotation,0]) difference(){
union(){
BodyTop();
// **** Add your bottom top additions here ****
//cylinder(h=18,d=10,center = true); // Example
}
// **** Add your top case cuts here ****
//cylinder(h=20,d=5,center = true); // Example
}
//===============================================================================
// M O D U L E S
//===============================================================================
module ButtonCut(xpos,ypos) {
translate([xpos,ypos,17/2+BottomTopThickness+0.4])
{
cube([15.5,15,17],center=true);//key
translate([0,0,-17/2-2.5]) cylinder(d=10.5,h=5);
translate([0,0,-17/2-2.5+5/2+0.5]) rotate([0,0,45]) cube([5,14,5],center=true);
}
}
module ButtonSides (xpos,ypos) {
translate([xpos,ypos,17/2+2.5-0.1])
{
translate([0,0,-7+BottomTopThickness-0.1]) cube([15.5+2*2,15+2*2,7],center=true);//key
}
}
module BodyBottom () {
if(ShowBottom)
{
difference(){
union()
{
rotate([ 0, 0, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
if (EnableMountHolder)
{
color("SteelBlue")
if (MountHolderStyle!=5)
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
rotate([0,0,180]) translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
else
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
}
if (ShowDeviceHolder)
{
translate([DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
}
}
if (SeeNutCut) { color("red") translate([0,0,CaseHeight/2+CaseHeight-CutFromTop-NutSink]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight],center=true);}
if (SeeGrooveRidgeScrew) { color("red") translate([CaseRoundingRadius+50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth*2+0.1,CaseHeight+0.1],center=true);}
if (ShowSideWallHoles)
{
color("Yellow")
if(SideWallHolesOn_X)
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(XAdditionalScrew))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([-Caselength/4+CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
else
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/2-SideWallThickness/2,CaseWidth/4-CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
}
}
}
}
module BodyTop () {
if (ShowTop)
{
difference(){
union(){
rotate([ 0, 0, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
if (SeeGrooveRidgeScrew) { color("red") translate([-CaseRoundingRadius-50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight+0.1],center=true);}
}
}
}
module MountHolder (Thick,Hole) {
translate([0,0,0.005]) difference(){
if (MountHolderStyle==1){
$fn=40;
roundedBox([Caselength, MountHolderLenght*2, Thick*2], Thick/3, 0);
}
if (MountHolderStyle==2){
$fn=60;
roundedBox([Caselength, MountHolderLenght*2, Thick*2],CaseRoundingRadius , 1);
}
if (MountHolderStyle==3){
roundedBox([Caselength, MountHolderLenght*2, Thick*2],0 , 2);
}
if((MountHolderStyle>0)&&(MountHolderStyle<4)){
translate([0,0,-Thick/2-0.02]) cube([Caselength+0.02,MountHolderLenght*2+0.02,Thick+0.04],center=true);
translate([0,-MountHolderLenght/2-CaseRoundingRadius,Thick/2+0.02]) cube([Caselength+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-MountHolderLenght/2,Thick/2+0.02]) cube([Caselength-2*CaseRoundingRadius+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
mirror([ 1, 0, 0]) translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
if (CountOfMountHolderHoles>1){
translate([Caselength/2-Hole-Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([-Caselength/2+Hole+Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
if (CountOfMountHolderHoles!=2){
translate([0,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
if (MountHolderStyle==4){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference(){
union(){
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
translate([0,-MountHolderLenght+Hole*1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
if (MountHolderStyle==5){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*4+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([-Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([+Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
rotate([0,0,180]) translate([0,MountHolderLenght+CaseWidth,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([0,-MountHolderLenght+Hole*1.6+Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([0,-MountHolderLenght+Hole*1.6-Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
}
module ShowSizes () {
echo ();
echo (str(" Stable and waterproof OpenSCAD case by pbtec V6.0"));
echo ();
echo (str(" Render quality : ",$fn));
echo ();
echo (str(" --> Case outer dimensions: "));
echo (str(" Length : ",Caselength,"mm "));
echo (str(" Width : ",CaseWidth,"mm "));
echo (str(" High : ",CaseHeight,"mm "));
echo (str(" Top (upper piece) high : ",CutFromTop,"mm "));
echo (str(" Bottom (lower piece) high : ",CaseHeight-CutFromTop,"mm "));
echo (str(" Side wall thickness : ",SideWallThickness,"mm "));
echo (str(" Bottom & top wall thickness : ",BottomTopThickness,"mm "));
echo (str(" Case rounding radius : ",CaseRoundingRadius,"mm "));
echo ();
echo (str(" --> Case inner dimensions : "));
echo (str(" X : Wall to wall : ",Caselength-2*SideWallThickness,"mm "));
echo (str(" X : Screw cylinder to screw cylinder : ",Caselength-4*CaseRoundingRadius,"mm "));
echo (str(" Y : Wall to wall : ",CaseWidth-2*SideWallThickness,"mm "));
echo (str(" Y : Screw cylinder to screw cylinder : ",CaseWidth-4*CaseRoundingRadius,"mm "));
echo (str(" Top to bottom : ",CaseHeight-2*BottomTopThickness,"mm "));
echo ();
echo (str(" <b>Screw dimensions : "));
echo (str(" Metric Screw size: m",CountersinkScrew));
echo (str(" Screw hole diameter : ",ScrewHoleDia,"mm "));
echo (str(" Screw head diameter : ",ScrewHeadDia,"mm "));
echo (str(" X : Additional screw (3rd)) : ",XAdditionalScrew));
echo (str(" Y : Additional screws (3rd) : ",YAdditionalScrew));
echo (str(" --> Check if you have screws within the following size : "));
echo (str(" --> Screw m",CountersinkScrew , " max length : ",CaseHeight-BottomTopThickness, "mm"));
if(UseSquareNutInsteadOfNut) { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+SquareNutHigh, "mm")); }
else { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+NutHigh, "mm")); }
}
module GrooveStraight (length) {
color("orange") translate([length/2,0,-(GrooveDepth+AddGrooveDepthForSealing)/2]) cube([length,GrooveWidth,GrooveDepth+AddGrooveDepthForSealing],center=true);
}
module GrooveCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,-(GrooveDepth+AddGrooveDepthForSealing)]) pie(Rad+(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing, spin=0);
translate([-0.01,-0.01,-(GrooveDepth+AddGrooveDepthForSealing+0.02)]) pie(Rad-(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing+0.04, spin=0);
}
}
module RidgeStraight (length) {
color("orange") translate([length/2,0,(RidgeHeight)/2]) cube([length,RidgeWidth,RidgeHeight],center=true);
}
module RidgeCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,0]) pie(Rad+(RidgeWidth)/2, Angle, RidgeHeight, spin=0);
translate([-0.01,-0.01,-0.02]) pie(Rad-(RidgeWidth)/2, Angle, RidgeHeight+0.04, spin=0);
}
}
module BodyQuarterBottom (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference(){
union(){
color("SteelBlue")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) RidgeCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.00,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);}
}
if(UseSquareNutInsteadOfNut)
{
if (EdgeSquareNutInsertFrom_X) {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0, 0]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
if (XAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
if (YAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
}
}
module BodyQuarterTop (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference()
{
union(){
color("DarkCyan")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
translate(ScrewCornerPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
if (XAdditionalScrew){
translate(ScrewAddXPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
if (YAdditionalScrew){
translate(ScrewAddYPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) GrooveCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.07);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.057);
}
}
}
module BodyQuarter (L,W,H,Rad,Rand){
cube([L/2-Rad,W/2,BottomTopThickness],center=false); // Ground
cube([L/2,W/2-Rad,BottomTopThickness],center=false); // Ground
if (CaseRadius < CaseRoundingRadius)
{
translate([0,W/2-Rand,0]) cube([L/2-CaseRadius,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-CaseRadius,H],center=false); // Wall
translate([L/2-CaseRadius,W/2-CaseRadius,H/2]) cylinder(h=H,r=CaseRadius,center = true);
}
else
{
translate([0,W/2-Rand,0]) cube([L/2-Rad,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-Rad,H],center=false); // Wall
}
translate(ScrewCornerPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+Rand,W/2-Rad,0]) rotate([0,0, 0]) HolderGap(H,Rad,Rand); // Gap between wall and Cylinder
translate([L/2-Rad,W/2-Rad-Rand,0]) rotate([0,0,-90]) HolderGap(H,Rad,Rand); // Gap Between wall and Cylinder
if (XAdditionalScrew) {
translate(ScrewAddXPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([Rand,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
translate([Rand-2*CaseRoundingRadius,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
}
if (YAdditionalScrew) {
translate(ScrewAddYPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand+2*CaseRoundingRadius,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
}
}
module NutCut(TotalHigh,High,Dia){
AdditionalGap=0.3;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink]) cylinder($fn=6,h=High+2*AdditionalGap,d=2*sqrt(((Dia/2)*(Dia/2))+((Dia/4)*(Dia/4)))+Dia/26+2*AdditionalGap,center = true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SquareNutCut (TotalHigh,High,Size) {
AdditionalGap=0.5;
SquareNutInsertReduction= 0.2;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink])cube([Size+2*AdditionalGap,Size+2*AdditionalGap,High+2*AdditionalGap],center=true);
translate([CaseRoundingRadius/2+0.02,0,-(High+2*AdditionalGap)/2-NutSink+SquareNutInsertReduction/2]) cube([CaseRoundingRadius+0.04,Size+2*AdditionalGap,High+2*AdditionalGap-SquareNutInsertReduction],center=true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SideWallHoles () {
cylinder(h=20,d1=10,d2=15,center = true);
}
module ScrewCut(m,h,v){
// m = 3=M3 4=M4 5=M5 6=M6 usw...
// h = High of the screw inkl. head
// v = if screw head is to be sunk deeper
ScrewHeadDia=m*2; // Berechnung des Schraubenkopf Durchmessers
//ScrewCountersink=(m+8)/14-0.7; // Leichte ScrewCountersink damit Schraube nicht vorsteht
ScrewHoleDia=m+1; // ScrewHoleDiadurchmesser
translate([0,0,-0.01]) union(){ // Ganze Schraube
translate([0,0,ScrewCountersink-0.01])cylinder( h = ScrewHeadDia/4,d1=ScrewHeadDia,d2=ScrewHeadDia/2,center=false); // Kegel (Abschraegung)
translate([0,0,0]) cylinder( h = ScrewCountersink,d=ScrewHeadDia,center=false); // ScrewCountersink
translate([0,0,0.01])rotate([180,0,0])cylinder(h=v,d=ScrewHeadDia,center = false); // Versenkung
translate([0,0,0.01])cylinder( h = h,d=ScrewHoleDia,center=false); //Loch fuer Gewinde
}
}
module HolderGap (H,Rad,Rand) {
difference(){
translate([0,0,0]) cube([Rad*2-2*Rand,Rad-Rand,H],center=false);
translate([0,0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
translate([2*(Rad-Rand),0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
}
}
module DeviceHolder () {
color("yellow")translate([0,0,ScrewCylinderHeight/2+BottomTopThickness]) difference(){
cylinder(h=ScrewCylinderHeight,d=ScrewCylinderDiameter,center = true);
translate([0,0,0]) cylinder(h=ScrewCylinderHeight+0.05,d=ScrewHoleDiameter,center = true);
}
}
module pie(radius, angle, height, spin=0) {
// Negative angles shift direction of rotation
clockwise = (angle < 0) ? true : false;
// Support angles < 0 and > 360
normalized_angle = abs((angle % 360 != 0) ? angle % 360 : angle % 360 + 360);
// Select rotation direction
rotation = clockwise ? [0, 180 - normalized_angle] : [180, normalized_angle];
// Render
if (angle != 0) {
rotate([0,0,spin]) linear_extrude(height=height)
difference() {
circle(radius);
if (normalized_angle < 180) {
union() for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
else if (normalized_angle != 360) {
intersection_for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
}
}
}
module roundedBox(size, radius, sidesonly) // Laenge, Breite, Hoehe, Radius, 0/1
{
rot = [ [0,0,0], [90,0,90], [90,90,0] ];
if (sidesonly) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
else {
cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);
for (axis = [0:2]) {
for (x = [radius-size[axis]/2, -radius+size[axis]/2],
y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
rotate(rot[axis])
translate([x,y,0])
cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
}
}
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2],
z = [radius-size[2]/2, -radius+size[2]/2]) {
translate([x,y,z]) sphere(radius);
}
}
}

BIN
cad/20241018_case.3mf Normal file

Binary file not shown.

85710
cad/20241018_case.stl Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

1386
cad/20241018_keycap.step Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

88650
cad/20241019_case.stl Normal file

File diff suppressed because it is too large Load diff

5089
cad/20241020_keycap.step Normal file

File diff suppressed because it is too large Load diff

2978
cad/case.csg Normal file

File diff suppressed because it is too large Load diff

833
cad/case.scad Normal file
View file

@ -0,0 +1,833 @@
/*******************************************************************************
TITLE:
Stable and waterproof OpenSCAD case by pbtec
DESCRIPTION:
highly scalable case for 3D printing. Try it out!
Optimized for Openscad Customizer. Activate it under view/customizer and play around ;-)
No Support needed to print
- for waterproof cases you can use silicone sealing cord with diameters from 1 to 3mm
- to use also without sealing cord. The groove and ridge gives the housing a high stability and tightness.
- Use of regular nuts or square nuts
- define outer vertical radius of corners
- echo output in console shows inner and outer size and more
- echo output shows the needed length of the screws
- use screws from m2 up to m5
- default are 4 screws at each corner. For large cases add addtional ones in the middle of both x and y sides if needed
- use several predefined wall mount holder, some with multiple mounting holes (up to 3)
Important!
- If you use standard nuts you need to pause the printer a certain level to insert the nuts
- If you need a stable and waterproof case please print with 100% infill
- I'm aware that sometimes, when using too big or too small parameters, there are some rendering issues.
To prevent such issues change only one parameter at once and check the result.
for waterproofness see https://blog.prusaprinters.org/watertight-3d-printing-part-2_53638/
AUTHOR:
pbtec / pb-tec.ch
use https://paypal.me/pbtec if you want to spend me a coold beer. Thanks in advance :-)
VERSION:
V KZZ DATE COMMENT
6.0 pb 31.07.21 First Version to share
*******************************************************************************/
use <fillets3d.scad>;
/* [View settings] */
// Shows the Bottom of the case
ShowBottom = true;
// Shows the top of the case
ShowTop = true;
// Distance between top and bottom (if both are side by side displayed)
DistanceBetweenObjects = 10;
// Shows the housing assembled
ShowCaseAssembled = false;
/* [Control cuts (use only one at a time)] */
// To see the nuts inside (best view if not assembled showed)
SeeNutCut = false;
// To see the groove, ridge and Screw (best view if assembled showed)
SeeGrooveRidgeScrew = false;
/* [Case settings] */
// Length of the case
Caselength = 60;
// Width of the case
CaseWidth = 100;
// Height of the case
CaseHeight = 28;
// Splitt the Case height into bottom and top, check for the needed screws in echo output (console)
CutFromTop = 5.0;
// Thickness for the bottom and top wall (vertical walls needs to be calculated)
BottomTopThickness = 2.0;
// If this is bigger than the needed cylinder around the screw it will be ignored
CaseRadius = 12.0;
/* [Case Screw settings] */
//2=m2/2.5=m2.5/3=m3/4=m4/5=m5 // max m5, larger sizes do not fit
CountersinkScrew = 3.0; // [2:m2, 2.5: m2.5, 3: m3, 4: m4, 5: m5]
// Adds additional Screws on X axis (for large cases) --> Try it out
XAdditionalScrew = false; // can be true or false / Adds additional Screws on X axis (for large cases) --> Try it out
// Adds additional Screws on Y axis (for large cases) --> Try it out
YAdditionalScrew = false; // can be true or false / Adds additional Screws on Y axis (for large cases) --> Try it out
/* [Groove settings] */
// If using a SealingCord use the SealingCord diameter, otherwise x-times of your 3D Printer Nozzle (0.8/1.2/...) --> Ridge gets perfect for printing
GrooveWidth = 1.2; // [0.8:0.1:3]
// Not less than 1mm (for stability) and not more than 3mm --> Best 2mm
GrooveDepth = 2.0; // [1.0:0.1:3]
// Space between Groove and Ridge for a perfect fit, usualy 0.2 or 0.3 for FDM depending on your printer quality
Space = 0.3; // [0.0:0.1:0.4]
// Addtional vertical room for the pressed sealing Cord. For sealing cord 1.5mm -->0.5 // for 2mm -->0.8 // for 2.5 -->1.0 // If no sealing cord then set this parameter to 0.
AddGrooveDepthForSealing = 0.8; // [0.0:0.1:3]
// Range Inside groove/ridge. Usualy 2 times or more the printer nozzle. For best stability at least 0.8
InnerBorder = 0.8; // [0.8:0.1:4]
// Range Outside groove/ridge . Usualy 2 times or more the printer nozzle. For best stability at least 0.8
OuterBorder = 0.8; // [0.8:0.1:4]
/* [Nut general settings] */
// Size of material (plastic) above nut/square nut (3mm or more). The more, the more stable but need longer screw.
NutSink = 4.0;
/* [Standard nut settings] */
// Nut Settings / As there are (or I have) many different nuts dimensions, the size must be specified / Do not add separation space, only the real measurement // m2=1.5 // m2.5=1.9 // m3=2.4 // m4=3.2 // n5=3.8
NutHigh = 2.4;
// Distance between the paralell sides / Do not add separation space, only the real measurement // m2=3.8 // m2.5=4.9 // m3=5.4 // m4=6.9 // m5=7.9
NutDia = 5.4;
/* [Square Nut settings] */
// Select if you want to use square nuts instead of normal nuts
UseSquareNutInsteadOfNut = true;
// Select the high of the square nut / Do not add separation space, only the real measurement
SquareNutHigh = 1.9;
// Select the size of the square nut / Do not add separation space, only the real measurement
SquareNutSize = 5.4;
// Square nut insert from which side
EdgeSquareNutInsertFrom_X = true;
/* [Wall mount holder settings] */
// Select if you need a mount holder
EnableMountHolder = false;
// Chose your desired wall mount style
MountHolderStyle = 5; // [1:Style 1, 2: Style 2, 3: Style 3, 4 : Style 4, 5 : Style 5]
// Some styles (1-3) allow more than one hole
CountOfMountHolderHoles = 1; // [1:One hole centered, 2: Two holes, 3: Three holes]
MountHolderHoleDiameter = 5; // [1:0.1:10]
MountHolderThickness = 4.0; // [2:0.1:10]
/* [PCB/Device holder settings] */
// Activate customizable PCB/Device holder
ShowDeviceHolder = false;
// Hole in the cylinder for the screw // 2.9 Screw = 2mm hole
ScrewHoleDiameter = 2.6;
// The diamter of the screw cylinder
ScrewCylinderDiameter = 7;
// The height of the screw cylinders (also the deepness for the screw hole)
ScrewCylinderHeight = 8.0;
// Distance between the holders in X direction
DeviceHolder_X_Distance = 60;
// Distance between the holders in Y direction
DeviceHolder_y_Distance = 80;
// Move all holders in X direction
Offset_X = 0;
// Move all holders in Y direction
Offset_Y = -20;
/* [Wall Holes settings (for cable gland cut)] */
// Activate customizable holes for cable gland or similar
ShowSideWallHoles = false;
// Holes on X or Y side of the housing
SideWallHolesOn_X = false;
// Count of holes, if there is an additional screw on X or Y side the hole in the middle is not showed
CountOfSideWallHoles = 1; //[1:1:3]
// Diameter of the holes
SideWallHoleDiameter = 16.5; //[1:0.1:80]
// Add or decrease height position
SiedWallHoleOffset_Z = 0;
/* [Render quality settings] */
// Set to at least to 150 before render and save as .stl file, otherwise you can go down to 40 for quick 3D view
$fn = 60; // [20:1:300]
// ========================= C A L C U L A T E D S E T T I N G S (do not change!!!) ===================================
// Calculated Screw settings (do not change!!!)
ScrewHoleDia = CountersinkScrew+1;
ScrewHeadDia = CountersinkScrew*2;
ScrewCountersink = (CountersinkScrew+8)/14-0.5;
// Calculated settings for Ridge (do not change!!!)
RidgeHeight = GrooveDepth-Space;
RidgeWidth = GrooveWidth-Space;
// Calculated settings for case (do not change!!!)
SideWallThickness = InnerBorder+GrooveWidth+OuterBorder;
CaseRoundingRadius = ScrewHoleDia/2+InnerBorder+GrooveWidth+OuterBorder;
ScrewCornerPos = [Caselength/2-CaseRoundingRadius,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddXPos = [0,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddYPos = [Caselength/2-CaseRoundingRadius,0,0];
// Calculated settings for wall mount holder
MountHolderLenght = MountHolderHoleDiameter*3;
// if both objects showed
X_ObjectPosition = ((ShowBottom)&&(ShowTop)&&(!ShowCaseAssembled)) ? Caselength/2+DistanceBetweenObjects/2:0;
// If the case is assembled showed
Y_TopRotation = ShowCaseAssembled ? 180:0;
Z_TopHigh = ShowCaseAssembled ? CaseHeight:0;
ShowSizes(); // Show the calculated sizes
//===============================================================================
// M A I N
//===============================================================================
/*
translate([X_ObjectPosition,0,0]) rotate([0,0,0]) difference(){
RoundCaselength=Caselength+0.1;
RoundCaseWidth=CaseWidth+0.1;
RoundCaseRadius=CaseRadius*0.8;
shellthickness=5;
casebottomradius=3;
difference(){
translate([0,0,casebottomradius/2]) cube([RoundCaselength+2*shellthickness,RoundCaseWidth+2*shellthickness,casebottomradius+shellthickness],center=true);
{
topBottomFillet(t=CaseHeight,b=0, r=casebottomradius, s=10)
minkowski()
{
translate([0,0,CaseHeight/2]) cube([RoundCaselength-RoundCaseRadius,RoundCaseWidth-RoundCaseRadius,CaseHeight],center=true);
cylinder(r=RoundCaseRadius/2,h=1);
}
}
}
}*/
// Button Bar
// --> Show the bottom of the case
translate([X_ObjectPosition,0,0]) rotate([0,0,0])
//topBottomFillet(t=CaseHeight,b=0, r=3, s=15)
difference(){
union(){
BodyBottom();
// **** Add your bottom case additions here ****
//cylinder(h=20,d=15,center = true); // Example
//#translate([-18,0,18/2+2]) rotate([90,0,0]) cylinder(h=70,d=18,center=true); //battery mockup
translate([-7.5,0,20/2+0.1]) cube([2,CaseWidth-4,20],center=true); //battery divider
translate([-18,CaseWidth/2-12, 20/2+0.1]) cube([20,4,20],center=true); //battery ends
translate([-18,-(CaseWidth/2-12),20/2+0.1]) cube([20,4,20],center=true); //battery ends
translate([0,10,16/2+BottomTopThickness]) cube([6,26+4,16],center=true); //wemos walls
translate([20.75,10,16/2+BottomTopThickness]) cube([6,26+4,16],center=true); //wemos walls
translate([-7.5+2+1,-(CaseWidth/2-31/2-0.1),15/2+0.1]) cube([5,31,15],center=true); //charge board wall
ButtonSides(14,-(15+2)*2);
ButtonSides(14,-(15+2)*1);
//ButtonSides(14,0);
//ButtonSides(14,(15+2)*1);
ButtonSides(14,(15+2)*2);
}
// **** Add your bottom case cuts here ****
//cylinder(h=15,d=20,center = true); // Example
ButtonCut(14,-(15+2)*2);
ButtonCut(14,-(15+2)*1);
//ButtonCut(14,0);
//ButtonCut(14,(15+2)*1);
ButtonCut(14,(15+2)*2);
translate([0,-14,-4+13]) {
//#translate([20,0,10]) cube([15,14,8],center=true); //switch case mockup
translate([20,0,10]) rotate([0,90,0]) cylinder(h=20,d=6); //on off switch
translate([27,6.5,10]) cube([2,2,2],center=true); //on off switch notch
}
translate([10-0.1,10,18/2+BottomTopThickness+0.1]) cube([34.5,26,18.1],center=true); //wemos
translate([-7.5+2,-(CaseWidth/2-28/2-0.5),17.5/2+BottomTopThickness+0.1]) cube([1.5,28,17.5],center=true); //charge board pcb
translate([-7.5+2.5,-(CaseWidth/2-4/2+0.1),17.5/2+BottomTopThickness+0.1]) cube([5,15,10],center=true); //charge board usb
translate([-7.5+2.5+0.01,-(CaseWidth/2-40/2-3),17.5/2+BottomTopThickness+0.1]) cube([3,40,17.5],center=true); //charge board
}
// --> Show the top of the case
translate([-X_ObjectPosition,0,Z_TopHigh+0.03]) rotate([0,Y_TopRotation,0]) difference(){
union(){
BodyTop();
// **** Add your bottom top additions here ****
//cylinder(h=18,d=10,center = true); // Example
}
// **** Add your top case cuts here ****
//cylinder(h=20,d=5,center = true); // Example
}
//===============================================================================
// M O D U L E S
//===============================================================================
module ButtonCut(xpos,ypos) {
translate([xpos,ypos,17/2+BottomTopThickness+0.39])
{
cube([15.5,15,17],center=true);//key
translate([0,0,-17/2-2.5]) cylinder(d=10.5,h=5);
translate([0,0,-17/2-2.5+5/2+0.5]) rotate([0,0,45]) cube([5,14,5],center=true);
}
}
module ButtonSides (xpos,ypos) {
translate([xpos,ypos,17/2+2.5-0.1])
{
translate([0,0,-7+BottomTopThickness-0.1]) cube([15.5+2*2,15+2*2,7],center=true);//key
}
}
module BodyBottom () {
if(ShowBottom)
{
difference(){
union()
{
rotate([ 0, 0, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
if (EnableMountHolder)
{
color("SteelBlue")
if (MountHolderStyle!=5)
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
rotate([0,0,180]) translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
else
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
}
if (ShowDeviceHolder)
{
translate([DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
}
}
if (SeeNutCut) { color("red") translate([0,0,CaseHeight/2+CaseHeight-CutFromTop-NutSink]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight],center=true);}
if (SeeGrooveRidgeScrew) { color("red") translate([CaseRoundingRadius+50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth*2+0.1,CaseHeight+0.1],center=true);}
if (ShowSideWallHoles)
{
color("Yellow")
if(SideWallHolesOn_X)
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(XAdditionalScrew))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([-Caselength/4+CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
else
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/2-SideWallThickness/2,CaseWidth/4-CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
}
}
}
}
module BodyTop () {
if (ShowTop)
{
difference(){
union(){
rotate([ 0, 0, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
if (SeeGrooveRidgeScrew) { color("red") translate([-CaseRoundingRadius-50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight+0.1],center=true);}
}
}
}
module MountHolder (Thick,Hole) {
translate([0,0,0.005]) difference(){
if (MountHolderStyle==1){
$fn=40;
roundedBox([Caselength, MountHolderLenght*2, Thick*2], Thick/3, 0);
}
if (MountHolderStyle==2){
$fn=60;
roundedBox([Caselength, MountHolderLenght*2, Thick*2],CaseRoundingRadius , 1);
}
if (MountHolderStyle==3){
roundedBox([Caselength, MountHolderLenght*2, Thick*2],0 , 2);
}
if((MountHolderStyle>0)&&(MountHolderStyle<4)){
translate([0,0,-Thick/2-0.02]) cube([Caselength+0.02,MountHolderLenght*2+0.02,Thick+0.04],center=true);
translate([0,-MountHolderLenght/2-CaseRoundingRadius,Thick/2+0.02]) cube([Caselength+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-MountHolderLenght/2,Thick/2+0.02]) cube([Caselength-2*CaseRoundingRadius+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
mirror([ 1, 0, 0]) translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
if (CountOfMountHolderHoles>1){
translate([Caselength/2-Hole-Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([-Caselength/2+Hole+Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
if (CountOfMountHolderHoles!=2){
translate([0,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
if (MountHolderStyle==4){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference(){
union(){
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
translate([0,-MountHolderLenght+Hole*1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
if (MountHolderStyle==5){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*4+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([-Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([+Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
rotate([0,0,180]) translate([0,MountHolderLenght+CaseWidth,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([0,-MountHolderLenght+Hole*1.6+Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([0,-MountHolderLenght+Hole*1.6-Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
}
module ShowSizes () {
echo ();
echo (str(" Stable and waterproof OpenSCAD case by pbtec V6.0"));
echo ();
echo (str(" Render quality : ",$fn));
echo ();
echo (str(" --> Case outer dimensions: "));
echo (str(" Length : ",Caselength,"mm "));
echo (str(" Width : ",CaseWidth,"mm "));
echo (str(" High : ",CaseHeight,"mm "));
echo (str(" Top (upper piece) high : ",CutFromTop,"mm "));
echo (str(" Bottom (lower piece) high : ",CaseHeight-CutFromTop,"mm "));
echo (str(" Side wall thickness : ",SideWallThickness,"mm "));
echo (str(" Bottom & top wall thickness : ",BottomTopThickness,"mm "));
echo (str(" Case rounding radius : ",CaseRoundingRadius,"mm "));
echo ();
echo (str(" --> Case inner dimensions : "));
echo (str(" X : Wall to wall : ",Caselength-2*SideWallThickness,"mm "));
echo (str(" X : Screw cylinder to screw cylinder : ",Caselength-4*CaseRoundingRadius,"mm "));
echo (str(" Y : Wall to wall : ",CaseWidth-2*SideWallThickness,"mm "));
echo (str(" Y : Screw cylinder to screw cylinder : ",CaseWidth-4*CaseRoundingRadius,"mm "));
echo (str(" Top to bottom : ",CaseHeight-2*BottomTopThickness,"mm "));
echo ();
echo (str(" <b>Screw dimensions : "));
echo (str(" Metric Screw size: m",CountersinkScrew));
echo (str(" Screw hole diameter : ",ScrewHoleDia,"mm "));
echo (str(" Screw head diameter : ",ScrewHeadDia,"mm "));
echo (str(" X : Additional screw (3rd)) : ",XAdditionalScrew));
echo (str(" Y : Additional screws (3rd) : ",YAdditionalScrew));
echo (str(" --> Check if you have screws within the following size : "));
echo (str(" --> Screw m",CountersinkScrew , " max length : ",CaseHeight-BottomTopThickness, "mm"));
if(UseSquareNutInsteadOfNut) { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+SquareNutHigh, "mm")); }
else { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+NutHigh, "mm")); }
}
module GrooveStraight (length) {
color("orange") translate([length/2,0,-(GrooveDepth+AddGrooveDepthForSealing)/2]) cube([length,GrooveWidth,GrooveDepth+AddGrooveDepthForSealing],center=true);
}
module GrooveCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,-(GrooveDepth+AddGrooveDepthForSealing)]) pie(Rad+(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing, spin=0);
translate([-0.01,-0.01,-(GrooveDepth+AddGrooveDepthForSealing+0.02)]) pie(Rad-(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing+0.04, spin=0);
}
}
module RidgeStraight (length) {
color("orange") translate([length/2,0,(RidgeHeight)/2]) cube([length,RidgeWidth,RidgeHeight],center=true);
}
module RidgeCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,0]) pie(Rad+(RidgeWidth)/2, Angle, RidgeHeight, spin=0);
translate([-0.01,-0.01,-0.02]) pie(Rad-(RidgeWidth)/2, Angle, RidgeHeight+0.04, spin=0);
}
}
module BodyQuarterBottom (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference(){
union(){
color("SteelBlue")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) RidgeCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.00,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);}
}
if(UseSquareNutInsteadOfNut)
{
if (EdgeSquareNutInsertFrom_X) {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0, 0]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
if (XAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
if (YAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
}
}
module BodyQuarterTop (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference()
{
union(){
color("DarkCyan")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
translate(ScrewCornerPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
if (XAdditionalScrew){
translate(ScrewAddXPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
if (YAdditionalScrew){
translate(ScrewAddYPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) GrooveCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.07);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.057);
}
}
}
module BodyQuarter (L,W,H,Rad,Rand){
cube([L/2-Rad,W/2,BottomTopThickness],center=false); // Ground
cube([L/2,W/2-Rad,BottomTopThickness],center=false); // Ground
if (CaseRadius < CaseRoundingRadius)
{
translate([0,W/2-Rand,0]) cube([L/2-CaseRadius,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-CaseRadius,H],center=false); // Wall
translate([L/2-CaseRadius,W/2-CaseRadius,H/2]) cylinder(h=H,r=CaseRadius,center = true);
}
else
{
translate([0,W/2-Rand,0]) cube([L/2-Rad,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-Rad,H],center=false); // Wall
}
translate(ScrewCornerPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+Rand,W/2-Rad,0]) rotate([0,0, 0]) HolderGap(H,Rad,Rand); // Gap between wall and Cylinder
translate([L/2-Rad,W/2-Rad-Rand,0]) rotate([0,0,-90]) HolderGap(H,Rad,Rand); // Gap Between wall and Cylinder
if (XAdditionalScrew) {
translate(ScrewAddXPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([Rand,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
translate([Rand-2*CaseRoundingRadius,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
}
if (YAdditionalScrew) {
translate(ScrewAddYPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand+2*CaseRoundingRadius,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
}
}
module NutCut(TotalHigh,High,Dia){
AdditionalGap=0.3;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink]) cylinder($fn=6,h=High+2*AdditionalGap,d=2*sqrt(((Dia/2)*(Dia/2))+((Dia/4)*(Dia/4)))+Dia/26+2*AdditionalGap,center = true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SquareNutCut (TotalHigh,High,Size) {
AdditionalGap=0.5;
SquareNutInsertReduction= 0.2;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink])cube([Size+2*AdditionalGap,Size+2*AdditionalGap,High+2*AdditionalGap],center=true);
translate([CaseRoundingRadius/2+0.02,0,-(High+2*AdditionalGap)/2-NutSink+SquareNutInsertReduction/2]) cube([CaseRoundingRadius+0.04,Size+2*AdditionalGap,High+2*AdditionalGap-SquareNutInsertReduction],center=true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SideWallHoles () {
cylinder(h=20,d1=10,d2=15,center = true);
}
module ScrewCut(m,h,v){
// m = 3=M3 4=M4 5=M5 6=M6 usw...
// h = High of the screw inkl. head
// v = if screw head is to be sunk deeper
ScrewHeadDia=m*2; // Berechnung des Schraubenkopf Durchmessers
//ScrewCountersink=(m+8)/14-0.7; // Leichte ScrewCountersink damit Schraube nicht vorsteht
ScrewHoleDia=m+1; // ScrewHoleDiadurchmesser
translate([0,0,-0.01]) union(){ // Ganze Schraube
translate([0,0,ScrewCountersink-0.01])cylinder( h = ScrewHeadDia/4,d1=ScrewHeadDia,d2=ScrewHeadDia/2,center=false); // Kegel (Abschraegung)
translate([0,0,0]) cylinder( h = ScrewCountersink,d=ScrewHeadDia,center=false); // ScrewCountersink
translate([0,0,0.01])rotate([180,0,0])cylinder(h=v,d=ScrewHeadDia,center = false); // Versenkung
translate([0,0,0.01])cylinder( h = h,d=ScrewHoleDia,center=false); //Loch fuer Gewinde
}
}
module HolderGap (H,Rad,Rand) {
difference(){
translate([0,0,0]) cube([Rad*2-2*Rand,Rad-Rand,H],center=false);
translate([0,0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
translate([2*(Rad-Rand),0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
}
}
module DeviceHolder () {
color("yellow")translate([0,0,ScrewCylinderHeight/2+BottomTopThickness]) difference(){
cylinder(h=ScrewCylinderHeight,d=ScrewCylinderDiameter,center = true);
translate([0,0,0]) cylinder(h=ScrewCylinderHeight+0.05,d=ScrewHoleDiameter,center = true);
}
}
module pie(radius, angle, height, spin=0) {
// Negative angles shift direction of rotation
clockwise = (angle < 0) ? true : false;
// Support angles < 0 and > 360
normalized_angle = abs((angle % 360 != 0) ? angle % 360 : angle % 360 + 360);
// Select rotation direction
rotation = clockwise ? [0, 180 - normalized_angle] : [180, normalized_angle];
// Render
if (angle != 0) {
rotate([0,0,spin]) linear_extrude(height=height)
difference() {
circle(radius);
if (normalized_angle < 180) {
union() for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
else if (normalized_angle != 360) {
intersection_for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
}
}
}
module roundedBox(size, radius, sidesonly) // Laenge, Breite, Hoehe, Radius, 0/1
{
rot = [ [0,0,0], [90,0,90], [90,90,0] ];
if (sidesonly) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
else {
cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);
for (axis = [0:2]) {
for (x = [radius-size[axis]/2, -radius+size[axis]/2],
y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
rotate(rot[axis])
translate([x,y,0])
cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
}
}
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2],
z = [radius-size[2]/2, -radius+size[2]/2]) {
translate([x,y,z]) sphere(radius);
}
}
}

View file

@ -0,0 +1,750 @@
/*******************************************************************************
TITLE:
Stable and waterproof OpenSCAD case by pbtec
DESCRIPTION:
highly scalable case for 3D printing. Try it out!
Optimized for Openscad Customizer. Activate it under view/customizer and play around ;-)
No Support needed to print
- for waterproof cases you can use silicone sealing cord with diameters from 1 to 3mm
- to use also without sealing cord. The groove and ridge gives the housing a high stability and tightness.
- Use of regular nuts or square nuts
- define outer vertical radius of corners
- echo output in console shows inner and outer size and more
- echo output shows the needed length of the screws
- use screws from m2 up to m5
- default are 4 screws at each corner. For large cases add addtional ones in the middle of both x and y sides if needed
- use several predefined wall mount holder, some with multiple mounting holes (up to 3)
Important!
- If you use standard nuts you need to pause the printer a certain level to insert the nuts
- If you need a stable and waterproof case please print with 100% infill
- I'm aware that sometimes, when using too big or too small parameters, there are some rendering issues.
To prevent such issues change only one parameter at once and check the result.
for waterproofness see https://blog.prusaprinters.org/watertight-3d-printing-part-2_53638/
AUTHOR:
pbtec / pb-tec.ch
use https://paypal.me/pbtec if you want to spend me a coold beer. Thanks in advance :-)
VERSION:
V KZZ DATE COMMENT
6.0 pb 31.07.21 First Version to share
*******************************************************************************/
/* [View settings] */
// Shows the Bottom of the case
ShowBottom = true;
// Shows the top of the case
ShowTop = true;
// Distance between top and bottom (if both are side by side displayed)
DistanceBetweenObjects = 10;
// Shows the housing assembled
ShowCaseAssembled = false;
/* [Control cuts (use only one at a time)] */
// To see the nuts inside (best view if not assembled showed)
SeeNutCut = false;
// To see the groove, ridge and Screw (best view if assembled showed)
SeeGrooveRidgeScrew = false;
/* [Case settings] */
// Length of the case
Caselength = 60;
// Width of the case
CaseWidth = 100;
// Height of the case
CaseHeight = 40;
// Splitt the Case height into bottom and top, check for the needed screws in echo output (console)
CutFromTop = 10.0;
// Thickness for the bottom and top wall (vertical walls needs to be calculated)
BottomTopThickness = 3.0;
// If this is bigger than the needed cylinder around the screw it will be ignored
CaseRadius = 12.0;
/* [Case Screw settings] */
//2=m2/2.5=m2.5/3=m3/4=m4/5=m5 // max m5, larger sizes do not fit
CountersinkScrew = 3.0; // [2:m2, 2.5: m2.5, 3: m3, 4: m4, 5: m5]
// Adds additional Screws on X axis (for large cases) --> Try it out
XAdditionalScrew = false; // can be true or false / Adds additional Screws on X axis (for large cases) --> Try it out
// Adds additional Screws on Y axis (for large cases) --> Try it out
YAdditionalScrew = false; // can be true or false / Adds additional Screws on Y axis (for large cases) --> Try it out
/* [Groove settings] */
// If using a SealingCord use the SealingCord diameter, otherwise x-times of your 3D Printer Nozzle (0.8/1.2/...) --> Ridge gets perfect for printing
GrooveWidth = 1.2; // [0.8:0.1:3]
// Not less than 1mm (for stability) and not more than 3mm --> Best 2mm
GrooveDepth = 2.0; // [1.0:0.1:3]
// Space between Groove and Ridge for a perfect fit, usualy 0.2 or 0.3 for FDM depending on your printer quality
Space = 0.3; // [0.0:0.1:0.4]
// Addtional vertical room for the pressed sealing Cord. For sealing cord 1.5mm -->0.5 // for 2mm -->0.8 // for 2.5 -->1.0 // If no sealing cord then set this parameter to 0.
AddGrooveDepthForSealing = 0.8; // [0.0:0.1:3]
// Range Inside groove/ridge. Usualy 2 times or more the printer nozzle. For best stability at least 0.8
InnerBorder = 0.8; // [0.8:0.1:4]
// Range Outside groove/ridge . Usualy 2 times or more the printer nozzle. For best stability at least 0.8
OuterBorder = 0.8; // [0.8:0.1:4]
/* [Nut general settings] */
// Size of material (plastic) above nut/square nut (3mm or more). The more, the more stable but need longer screw.
NutSink = 4.0;
/* [Standard nut settings] */
// Nut Settings / As there are (or I have) many different nuts dimensions, the size must be specified / Do not add separation space, only the real measurement // m2=1.5 // m2.5=1.9 // m3=2.4 // m4=3.2 // n5=3.8
NutHigh = 2.4;
// Distance between the paralell sides / Do not add separation space, only the real measurement // m2=3.8 // m2.5=4.9 // m3=5.4 // m4=6.9 // m5=7.9
NutDia = 5.4;
/* [Square Nut settings] */
// Select if you want to use square nuts instead of normal nuts
UseSquareNutInsteadOfNut = false;
// Select the high of the square nut / Do not add separation space, only the real measurement
SquareNutHigh = 1.9;
// Select the size of the square nut / Do not add separation space, only the real measurement
SquareNutSize = 5.4;
// Square nut insert from which side
EdgeSquareNutInsertFrom_X = true;
/* [Wall mount holder settings] */
// Select if you need a mount holder
EnableMountHolder = false;
// Chose your desired wall mount style
MountHolderStyle = 5; // [1:Style 1, 2: Style 2, 3: Style 3, 4 : Style 4, 5 : Style 5]
// Some styles (1-3) allow more than one hole
CountOfMountHolderHoles = 1; // [1:One hole centered, 2: Two holes, 3: Three holes]
MountHolderHoleDiameter = 5; // [1:0.1:10]
MountHolderThickness = 4.0; // [2:0.1:10]
/* [PCB/Device holder settings] */
// Activate customizable PCB/Device holder
ShowDeviceHolder = false;
// Hole in the cylinder for the screw // 2.9 Screw = 2mm hole
ScrewHoleDiameter = 2.6;
// The diamter of the screw cylinder
ScrewCylinderDiameter = 7;
// The height of the screw cylinders (also the deepness for the screw hole)
ScrewCylinderHeight = 8.0;
// Distance between the holders in X direction
DeviceHolder_X_Distance = 60;
// Distance between the holders in Y direction
DeviceHolder_y_Distance = 80;
// Move all holders in X direction
Offset_X = 0;
// Move all holders in Y direction
Offset_Y = -20;
/* [Wall Holes settings (for cable gland cut)] */
// Activate customizable holes for cable gland or similar
ShowSideWallHoles = false;
// Holes on X or Y side of the housing
SideWallHolesOn_X = false;
// Count of holes, if there is an additional screw on X or Y side the hole in the middle is not showed
CountOfSideWallHoles = 1; //[1:1:3]
// Diameter of the holes
SideWallHoleDiameter = 16.5; //[1:0.1:80]
// Add or decrease height position
SiedWallHoleOffset_Z = 0;
/* [Render quality settings] */
// Set to at least to 150 before render and save as .stl file, otherwise you can go down to 40 for quick 3D view
$fn = 60; // [20:1:300]
// ========================= C A L C U L A T E D S E T T I N G S (do not change!!!) ===================================
// Calculated Screw settings (do not change!!!)
ScrewHoleDia = CountersinkScrew+1;
ScrewHeadDia = CountersinkScrew*2;
ScrewCountersink = (CountersinkScrew+8)/14-0.5;
// Calculated settings for Ridge (do not change!!!)
RidgeHeight = GrooveDepth-Space;
RidgeWidth = GrooveWidth-Space;
// Calculated settings for case (do not change!!!)
SideWallThickness = InnerBorder+GrooveWidth+OuterBorder;
CaseRoundingRadius = ScrewHoleDia/2+InnerBorder+GrooveWidth+OuterBorder;
ScrewCornerPos = [Caselength/2-CaseRoundingRadius,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddXPos = [0,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddYPos = [Caselength/2-CaseRoundingRadius,0,0];
// Calculated settings for wall mount holder
MountHolderLenght = MountHolderHoleDiameter*3;
// if both objects showed
X_ObjectPosition = ((ShowBottom)&&(ShowTop)&&(!ShowCaseAssembled)) ? Caselength/2+DistanceBetweenObjects/2:0;
// If the case is assembled showed
Y_TopRotation = ShowCaseAssembled ? 180:0;
Z_TopHigh = ShowCaseAssembled ? CaseHeight:0;
ShowSizes(); // Show the calculated sizes
//===============================================================================
// M A I N
//===============================================================================
// --> Show the bottom of the case
translate([X_ObjectPosition,0,0]) rotate([0,0,0]) difference(){
union(){
BodyBottom();
// **** Add your bottom case additions here ****
//cylinder(h=20,d=15,center = true); // Example
translate([-15,0,18/2+2]) rotate([90,0,0]) cylinder(h=70,d=18,center=true); //battery
cube([18,35,26]);
}
// **** Add your bottom case cuts here ****
//cylinder(h=15,d=20,center = true); // Example
}
// --> Show the top of the case
translate([-X_ObjectPosition,0,Z_TopHigh+0.03]) rotate([0,Y_TopRotation,0]) difference(){
union(){
BodyTop();
// **** Add your bottom top additions here ****
//cylinder(h=18,d=10,center = true); // Example
}
// **** Add your top case cuts here ****
//cylinder(h=20,d=5,center = true); // Example
}
//===============================================================================
// M O D U L E S
//===============================================================================
module BodyBottom () {
if(ShowBottom)
{
difference(){
union()
{
rotate([ 0, 0, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
if (EnableMountHolder)
{
color("SteelBlue")
if (MountHolderStyle!=5)
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
rotate([0,0,180]) translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
else
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
}
if (ShowDeviceHolder)
{
translate([DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
}
}
if (SeeNutCut) { color("red") translate([0,0,CaseHeight/2+CaseHeight-CutFromTop-NutSink]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight],center=true);}
if (SeeGrooveRidgeScrew) { color("red") translate([CaseRoundingRadius+50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth*2+0.1,CaseHeight+0.1],center=true);}
if (ShowSideWallHoles)
{
color("Yellow")
if(SideWallHolesOn_X)
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(XAdditionalScrew))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([-Caselength/4+CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
else
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/2-SideWallThickness/2,CaseWidth/4-CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
}
}
}
}
module BodyTop () {
if (ShowTop)
{
difference(){
union(){
rotate([ 0, 0, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
if (SeeGrooveRidgeScrew) { color("red") translate([-CaseRoundingRadius-50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight+0.1],center=true);}
}
}
}
module MountHolder (Thick,Hole) {
translate([0,0,0.005]) difference(){
if (MountHolderStyle==1){
$fn=40;
roundedBox([Caselength, MountHolderLenght*2, Thick*2], Thick/3, 0);
}
if (MountHolderStyle==2){
$fn=60;
roundedBox([Caselength, MountHolderLenght*2, Thick*2],CaseRoundingRadius , 1);
}
if (MountHolderStyle==3){
roundedBox([Caselength, MountHolderLenght*2, Thick*2],0 , 2);
}
if((MountHolderStyle>0)&&(MountHolderStyle<4)){
translate([0,0,-Thick/2-0.02]) cube([Caselength+0.02,MountHolderLenght*2+0.02,Thick+0.04],center=true);
translate([0,-MountHolderLenght/2-CaseRoundingRadius,Thick/2+0.02]) cube([Caselength+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-MountHolderLenght/2,Thick/2+0.02]) cube([Caselength-2*CaseRoundingRadius+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
mirror([ 1, 0, 0]) translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
if (CountOfMountHolderHoles>1){
translate([Caselength/2-Hole-Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([-Caselength/2+Hole+Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
if (CountOfMountHolderHoles!=2){
translate([0,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
if (MountHolderStyle==4){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference(){
union(){
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
translate([0,-MountHolderLenght+Hole*1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
if (MountHolderStyle==5){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*4+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([-Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([+Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
rotate([0,0,180]) translate([0,MountHolderLenght+CaseWidth,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([0,-MountHolderLenght+Hole*1.6+Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([0,-MountHolderLenght+Hole*1.6-Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
}
module ShowSizes () {
echo ();
echo (str(" Stable and waterproof OpenSCAD case by pbtec V6.0"));
echo ();
echo (str(" Render quality : ",$fn));
echo ();
echo (str(" --> Case outer dimensions: "));
echo (str(" Length : ",Caselength,"mm "));
echo (str(" Width : ",CaseWidth,"mm "));
echo (str(" High : ",CaseHeight,"mm "));
echo (str(" Top (upper piece) high : ",CutFromTop,"mm "));
echo (str(" Bottom (lower piece) high : ",CaseHeight-CutFromTop,"mm "));
echo (str(" Side wall thickness : ",SideWallThickness,"mm "));
echo (str(" Bottom & top wall thickness : ",BottomTopThickness,"mm "));
echo (str(" Case rounding radius : ",CaseRoundingRadius,"mm "));
echo ();
echo (str(" --> Case inner dimensions : "));
echo (str(" X : Wall to wall : ",Caselength-2*SideWallThickness,"mm "));
echo (str(" X : Screw cylinder to screw cylinder : ",Caselength-4*CaseRoundingRadius,"mm "));
echo (str(" Y : Wall to wall : ",CaseWidth-2*SideWallThickness,"mm "));
echo (str(" Y : Screw cylinder to screw cylinder : ",CaseWidth-4*CaseRoundingRadius,"mm "));
echo (str(" Top to bottom : ",CaseHeight-2*BottomTopThickness,"mm "));
echo ();
echo (str(" <b>Screw dimensions : "));
echo (str(" Metric Screw size: m",CountersinkScrew));
echo (str(" Screw hole diameter : ",ScrewHoleDia,"mm "));
echo (str(" Screw head diameter : ",ScrewHeadDia,"mm "));
echo (str(" X : Additional screw (3rd)) : ",XAdditionalScrew));
echo (str(" Y : Additional screws (3rd) : ",YAdditionalScrew));
echo (str(" --> Check if you have screws within the following size : "));
echo (str(" --> Screw m",CountersinkScrew , " max length : ",CaseHeight-BottomTopThickness, "mm"));
if(UseSquareNutInsteadOfNut) { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+SquareNutHigh, "mm")); }
else { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+NutHigh, "mm")); }
}
module GrooveStraight (length) {
color("orange") translate([length/2,0,-(GrooveDepth+AddGrooveDepthForSealing)/2]) cube([length,GrooveWidth,GrooveDepth+AddGrooveDepthForSealing],center=true);
}
module GrooveCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,-(GrooveDepth+AddGrooveDepthForSealing)]) pie(Rad+(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing, spin=0);
translate([-0.01,-0.01,-(GrooveDepth+AddGrooveDepthForSealing+0.02)]) pie(Rad-(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing+0.04, spin=0);
}
}
module RidgeStraight (length) {
color("orange") translate([length/2,0,(RidgeHeight)/2]) cube([length,RidgeWidth,RidgeHeight],center=true);
}
module RidgeCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,0]) pie(Rad+(RidgeWidth)/2, Angle, RidgeHeight, spin=0);
translate([-0.01,-0.01,-0.02]) pie(Rad-(RidgeWidth)/2, Angle, RidgeHeight+0.04, spin=0);
}
}
module BodyQuarterBottom (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference(){
union(){
color("SteelBlue")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) RidgeCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.00,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);}
}
if(UseSquareNutInsteadOfNut)
{
if (EdgeSquareNutInsertFrom_X) {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0, 0]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
if (XAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
if (YAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
}
}
module BodyQuarterTop (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference()
{
union(){
color("DarkCyan")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
translate(ScrewCornerPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
if (XAdditionalScrew){
translate(ScrewAddXPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
if (YAdditionalScrew){
translate(ScrewAddYPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) GrooveCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.07);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.057);
}
}
}
module BodyQuarter (L,W,H,Rad,Rand){
cube([L/2-Rad,W/2,BottomTopThickness],center=false); // Ground
cube([L/2,W/2-Rad,BottomTopThickness],center=false); // Ground
if (CaseRadius < CaseRoundingRadius)
{
translate([0,W/2-Rand,0]) cube([L/2-CaseRadius,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-CaseRadius,H],center=false); // Wall
translate([L/2-CaseRadius,W/2-CaseRadius,H/2]) cylinder(h=H,r=CaseRadius,center = true);
}
else
{
translate([0,W/2-Rand,0]) cube([L/2-Rad,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-Rad,H],center=false); // Wall
}
translate(ScrewCornerPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+Rand,W/2-Rad,0]) rotate([0,0, 0]) HolderGap(H,Rad,Rand); // Gap between wall and Cylinder
translate([L/2-Rad,W/2-Rad-Rand,0]) rotate([0,0,-90]) HolderGap(H,Rad,Rand); // Gap Between wall and Cylinder
if (XAdditionalScrew) {
translate(ScrewAddXPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([Rand,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
translate([Rand-2*CaseRoundingRadius,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
}
if (YAdditionalScrew) {
translate(ScrewAddYPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand+2*CaseRoundingRadius,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
}
}
module NutCut(TotalHigh,High,Dia){
AdditionalGap=0.3;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink]) cylinder($fn=6,h=High+2*AdditionalGap,d=2*sqrt(((Dia/2)*(Dia/2))+((Dia/4)*(Dia/4)))+Dia/26+2*AdditionalGap,center = true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SquareNutCut (TotalHigh,High,Size) {
AdditionalGap=0.5;
SquareNutInsertReduction= 0.2;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink])cube([Size+2*AdditionalGap,Size+2*AdditionalGap,High+2*AdditionalGap],center=true);
translate([CaseRoundingRadius/2+0.02,0,-(High+2*AdditionalGap)/2-NutSink+SquareNutInsertReduction/2]) cube([CaseRoundingRadius+0.04,Size+2*AdditionalGap,High+2*AdditionalGap-SquareNutInsertReduction],center=true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SideWallHoles () {
cylinder(h=20,d1=10,d2=15,center = true);
}
module ScrewCut(m,h,v){
// m = 3=M3 4=M4 5=M5 6=M6 usw...
// h = High of the screw inkl. head
// v = if screw head is to be sunk deeper
ScrewHeadDia=m*2; // Berechnung des Schraubenkopf Durchmessers
//ScrewCountersink=(m+8)/14-0.7; // Leichte ScrewCountersink damit Schraube nicht vorsteht
ScrewHoleDia=m+1; // ScrewHoleDiadurchmesser
translate([0,0,-0.01]) union(){ // Ganze Schraube
translate([0,0,ScrewCountersink-0.01])cylinder( h = ScrewHeadDia/4,d1=ScrewHeadDia,d2=ScrewHeadDia/2,center=false); // Kegel (Abschraegung)
translate([0,0,0]) cylinder( h = ScrewCountersink,d=ScrewHeadDia,center=false); // ScrewCountersink
translate([0,0,0.01])rotate([180,0,0])cylinder(h=v,d=ScrewHeadDia,center = false); // Versenkung
translate([0,0,0.01])cylinder( h = h,d=ScrewHoleDia,center=false); //Loch fuer Gewinde
}
}
module HolderGap (H,Rad,Rand) {
difference(){
translate([0,0,0]) cube([Rad*2-2*Rand,Rad-Rand,H],center=false);
translate([0,0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
translate([2*(Rad-Rand),0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
}
}
module DeviceHolder () {
color("yellow")translate([0,0,ScrewCylinderHeight/2+BottomTopThickness]) difference(){
cylinder(h=ScrewCylinderHeight,d=ScrewCylinderDiameter,center = true);
translate([0,0,0]) cylinder(h=ScrewCylinderHeight+0.05,d=ScrewHoleDiameter,center = true);
}
}
module pie(radius, angle, height, spin=0) {
// Negative angles shift direction of rotation
clockwise = (angle < 0) ? true : false;
// Support angles < 0 and > 360
normalized_angle = abs((angle % 360 != 0) ? angle % 360 : angle % 360 + 360);
// Select rotation direction
rotation = clockwise ? [0, 180 - normalized_angle] : [180, normalized_angle];
// Render
if (angle != 0) {
rotate([0,0,spin]) linear_extrude(height=height)
difference() {
circle(radius);
if (normalized_angle < 180) {
union() for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
else if (normalized_angle != 360) {
intersection_for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
}
}
}
module roundedBox(size, radius, sidesonly) // Laenge, Breite, Hoehe, Radius, 0/1
{
rot = [ [0,0,0], [90,0,90], [90,90,0] ];
if (sidesonly) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
else {
cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);
for (axis = [0:2]) {
for (x = [radius-size[axis]/2, -radius+size[axis]/2],
y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
rotate(rot[axis])
translate([x,y,0])
cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
}
}
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2],
z = [radius-size[2]/2, -radius+size[2]/2]) {
translate([x,y,z]) sphere(radius);
}
}
}

View file

@ -0,0 +1,788 @@
/*******************************************************************************
TITLE:
Stable and waterproof OpenSCAD case by pbtec
DESCRIPTION:
highly scalable case for 3D printing. Try it out!
Optimized for Openscad Customizer. Activate it under view/customizer and play around ;-)
No Support needed to print
- for waterproof cases you can use silicone sealing cord with diameters from 1 to 3mm
- to use also without sealing cord. The groove and ridge gives the housing a high stability and tightness.
- Use of regular nuts or square nuts
- define outer vertical radius of corners
- echo output in console shows inner and outer size and more
- echo output shows the needed length of the screws
- use screws from m2 up to m5
- default are 4 screws at each corner. For large cases add addtional ones in the middle of both x and y sides if needed
- use several predefined wall mount holder, some with multiple mounting holes (up to 3)
Important!
- If you use standard nuts you need to pause the printer a certain level to insert the nuts
- If you need a stable and waterproof case please print with 100% infill
- I'm aware that sometimes, when using too big or too small parameters, there are some rendering issues.
To prevent such issues change only one parameter at once and check the result.
for waterproofness see https://blog.prusaprinters.org/watertight-3d-printing-part-2_53638/
AUTHOR:
pbtec / pb-tec.ch
use https://paypal.me/pbtec if you want to spend me a coold beer. Thanks in advance :-)
VERSION:
V KZZ DATE COMMENT
6.0 pb 31.07.21 First Version to share
*******************************************************************************/
/* [View settings] */
// Shows the Bottom of the case
ShowBottom = true;
// Shows the top of the case
ShowTop = true;
// Distance between top and bottom (if both are side by side displayed)
DistanceBetweenObjects = 10;
// Shows the housing assembled
ShowCaseAssembled = false;
/* [Control cuts (use only one at a time)] */
// To see the nuts inside (best view if not assembled showed)
SeeNutCut = false;
// To see the groove, ridge and Screw (best view if assembled showed)
SeeGrooveRidgeScrew = false;
/* [Case settings] */
// Length of the case
Caselength = 60;
// Width of the case
CaseWidth = 100;
// Height of the case
CaseHeight = 40;
// Splitt the Case height into bottom and top, check for the needed screws in echo output (console)
CutFromTop = 5.0;
// Thickness for the bottom and top wall (vertical walls needs to be calculated)
BottomTopThickness = 2.0;
// If this is bigger than the needed cylinder around the screw it will be ignored
CaseRadius = 12.0;
/* [Case Screw settings] */
//2=m2/2.5=m2.5/3=m3/4=m4/5=m5 // max m5, larger sizes do not fit
CountersinkScrew = 3.0; // [2:m2, 2.5: m2.5, 3: m3, 4: m4, 5: m5]
// Adds additional Screws on X axis (for large cases) --> Try it out
XAdditionalScrew = false; // can be true or false / Adds additional Screws on X axis (for large cases) --> Try it out
// Adds additional Screws on Y axis (for large cases) --> Try it out
YAdditionalScrew = false; // can be true or false / Adds additional Screws on Y axis (for large cases) --> Try it out
/* [Groove settings] */
// If using a SealingCord use the SealingCord diameter, otherwise x-times of your 3D Printer Nozzle (0.8/1.2/...) --> Ridge gets perfect for printing
GrooveWidth = 1.2; // [0.8:0.1:3]
// Not less than 1mm (for stability) and not more than 3mm --> Best 2mm
GrooveDepth = 2.0; // [1.0:0.1:3]
// Space between Groove and Ridge for a perfect fit, usualy 0.2 or 0.3 for FDM depending on your printer quality
Space = 0.3; // [0.0:0.1:0.4]
// Addtional vertical room for the pressed sealing Cord. For sealing cord 1.5mm -->0.5 // for 2mm -->0.8 // for 2.5 -->1.0 // If no sealing cord then set this parameter to 0.
AddGrooveDepthForSealing = 0.8; // [0.0:0.1:3]
// Range Inside groove/ridge. Usualy 2 times or more the printer nozzle. For best stability at least 0.8
InnerBorder = 0.8; // [0.8:0.1:4]
// Range Outside groove/ridge . Usualy 2 times or more the printer nozzle. For best stability at least 0.8
OuterBorder = 0.8; // [0.8:0.1:4]
/* [Nut general settings] */
// Size of material (plastic) above nut/square nut (3mm or more). The more, the more stable but need longer screw.
NutSink = 4.0;
/* [Standard nut settings] */
// Nut Settings / As there are (or I have) many different nuts dimensions, the size must be specified / Do not add separation space, only the real measurement // m2=1.5 // m2.5=1.9 // m3=2.4 // m4=3.2 // n5=3.8
NutHigh = 2.4;
// Distance between the paralell sides / Do not add separation space, only the real measurement // m2=3.8 // m2.5=4.9 // m3=5.4 // m4=6.9 // m5=7.9
NutDia = 5.4;
/* [Square Nut settings] */
// Select if you want to use square nuts instead of normal nuts
UseSquareNutInsteadOfNut = false;
// Select the high of the square nut / Do not add separation space, only the real measurement
SquareNutHigh = 1.9;
// Select the size of the square nut / Do not add separation space, only the real measurement
SquareNutSize = 5.4;
// Square nut insert from which side
EdgeSquareNutInsertFrom_X = true;
/* [Wall mount holder settings] */
// Select if you need a mount holder
EnableMountHolder = false;
// Chose your desired wall mount style
MountHolderStyle = 5; // [1:Style 1, 2: Style 2, 3: Style 3, 4 : Style 4, 5 : Style 5]
// Some styles (1-3) allow more than one hole
CountOfMountHolderHoles = 1; // [1:One hole centered, 2: Two holes, 3: Three holes]
MountHolderHoleDiameter = 5; // [1:0.1:10]
MountHolderThickness = 4.0; // [2:0.1:10]
/* [PCB/Device holder settings] */
// Activate customizable PCB/Device holder
ShowDeviceHolder = false;
// Hole in the cylinder for the screw // 2.9 Screw = 2mm hole
ScrewHoleDiameter = 2.6;
// The diamter of the screw cylinder
ScrewCylinderDiameter = 7;
// The height of the screw cylinders (also the deepness for the screw hole)
ScrewCylinderHeight = 8.0;
// Distance between the holders in X direction
DeviceHolder_X_Distance = 60;
// Distance between the holders in Y direction
DeviceHolder_y_Distance = 80;
// Move all holders in X direction
Offset_X = 0;
// Move all holders in Y direction
Offset_Y = -20;
/* [Wall Holes settings (for cable gland cut)] */
// Activate customizable holes for cable gland or similar
ShowSideWallHoles = false;
// Holes on X or Y side of the housing
SideWallHolesOn_X = false;
// Count of holes, if there is an additional screw on X or Y side the hole in the middle is not showed
CountOfSideWallHoles = 1; //[1:1:3]
// Diameter of the holes
SideWallHoleDiameter = 16.5; //[1:0.1:80]
// Add or decrease height position
SiedWallHoleOffset_Z = 0;
/* [Render quality settings] */
// Set to at least to 150 before render and save as .stl file, otherwise you can go down to 40 for quick 3D view
$fn = 60; // [20:1:300]
// ========================= C A L C U L A T E D S E T T I N G S (do not change!!!) ===================================
// Calculated Screw settings (do not change!!!)
ScrewHoleDia = CountersinkScrew+1;
ScrewHeadDia = CountersinkScrew*2;
ScrewCountersink = (CountersinkScrew+8)/14-0.5;
// Calculated settings for Ridge (do not change!!!)
RidgeHeight = GrooveDepth-Space;
RidgeWidth = GrooveWidth-Space;
// Calculated settings for case (do not change!!!)
SideWallThickness = InnerBorder+GrooveWidth+OuterBorder;
CaseRoundingRadius = ScrewHoleDia/2+InnerBorder+GrooveWidth+OuterBorder;
ScrewCornerPos = [Caselength/2-CaseRoundingRadius,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddXPos = [0,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddYPos = [Caselength/2-CaseRoundingRadius,0,0];
// Calculated settings for wall mount holder
MountHolderLenght = MountHolderHoleDiameter*3;
// if both objects showed
X_ObjectPosition = ((ShowBottom)&&(ShowTop)&&(!ShowCaseAssembled)) ? Caselength/2+DistanceBetweenObjects/2:0;
// If the case is assembled showed
Y_TopRotation = ShowCaseAssembled ? 180:0;
Z_TopHigh = ShowCaseAssembled ? CaseHeight:0;
ShowSizes(); // Show the calculated sizes
//===============================================================================
// M A I N
//===============================================================================
// --> Show the bottom of the case
translate([X_ObjectPosition,0,0]) rotate([0,0,0]) difference(){
union(){
BodyBottom();
// **** Add your bottom case additions here ****
//cylinder(h=20,d=15,center = true); // Example
//#translate([-18,0,18/2+2]) rotate([90,0,0]) cylinder(h=70,d=18,center=true); //battery mockup
translate([-6,0,20/2+0.1]) cube([2,CaseWidth-4,20],center=true); //battery divider
translate([-15,CaseWidth/2-5.5,20/2+0.1]) cube([16,7,20],center=true); //battery ends
translate([-15,-(CaseWidth/2-5.5),20/2+0.1]) cube([16,7,20],center=true); //battery ends
//#translate([10,20,18/2+3+17-3]) cube([26,35,18],center=true); //wemos mockupo
ButtonSides(4,-(15+2)*2);
ButtonSides(4,-(15+2)*1);
//ButtonSides(4,0);
//ButtonSides(4,(15+2)*1);
ButtonSides(4,(15+2)*2);
}
// **** Add your bottom case cuts here ****
//cylinder(h=15,d=20,center = true); // Example
ButtonCut(4,-(15+2)*2);
ButtonCut(4,-(15+2)*1);
//ButtonCut(4,0);
//ButtonCut(4,(15+2)*1);
ButtonCut(4,(15+2)*2);
translate([20,0,10]) rotate([0,90,0]) cylinder(h=20,d=6); //on off switch
translate([27,6.5,10]) cube([2,2,2],center=true); //on off switch notch
}
// --> Show the top of the case
translate([-X_ObjectPosition,0,Z_TopHigh+0.03]) rotate([0,Y_TopRotation,0]) difference(){
union(){
BodyTop();
// **** Add your bottom top additions here ****
//cylinder(h=18,d=10,center = true); // Example
}
// **** Add your top case cuts here ****
//cylinder(h=20,d=5,center = true); // Example
}
//===============================================================================
// M O D U L E S
//===============================================================================
module ButtonCut(xpos,ypos) {
translate([xpos,ypos,17/2+BottomTopThickness+0.4])
{
cube([15.5,15,17],center=true);//key
translate([0,0,-17/2-2.5]) cylinder(d=10.5,h=5);
translate([0,0,-17/2-2.5+5/2+0.5]) rotate([0,0,45]) cube([5,14,5],center=true);
}
}
module ButtonSides (xpos,ypos) {
translate([xpos,ypos,17/2+2.5-0.1])
{
translate([0,0,-7+BottomTopThickness-0.1]) cube([15.5+2*2,15+2*2,7],center=true);//key
}
}
module BodyBottom () {
if(ShowBottom)
{
difference(){
union()
{
rotate([ 0, 0, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
if (EnableMountHolder)
{
color("SteelBlue")
if (MountHolderStyle!=5)
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
rotate([0,0,180]) translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
else
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
}
if (ShowDeviceHolder)
{
translate([DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
}
}
if (SeeNutCut) { color("red") translate([0,0,CaseHeight/2+CaseHeight-CutFromTop-NutSink]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight],center=true);}
if (SeeGrooveRidgeScrew) { color("red") translate([CaseRoundingRadius+50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth*2+0.1,CaseHeight+0.1],center=true);}
if (ShowSideWallHoles)
{
color("Yellow")
if(SideWallHolesOn_X)
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(XAdditionalScrew))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([-Caselength/4+CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
else
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/2-SideWallThickness/2,CaseWidth/4-CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
}
}
}
}
module BodyTop () {
if (ShowTop)
{
difference(){
union(){
rotate([ 0, 0, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
if (SeeGrooveRidgeScrew) { color("red") translate([-CaseRoundingRadius-50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight+0.1],center=true);}
}
}
}
module MountHolder (Thick,Hole) {
translate([0,0,0.005]) difference(){
if (MountHolderStyle==1){
$fn=40;
roundedBox([Caselength, MountHolderLenght*2, Thick*2], Thick/3, 0);
}
if (MountHolderStyle==2){
$fn=60;
roundedBox([Caselength, MountHolderLenght*2, Thick*2],CaseRoundingRadius , 1);
}
if (MountHolderStyle==3){
roundedBox([Caselength, MountHolderLenght*2, Thick*2],0 , 2);
}
if((MountHolderStyle>0)&&(MountHolderStyle<4)){
translate([0,0,-Thick/2-0.02]) cube([Caselength+0.02,MountHolderLenght*2+0.02,Thick+0.04],center=true);
translate([0,-MountHolderLenght/2-CaseRoundingRadius,Thick/2+0.02]) cube([Caselength+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-MountHolderLenght/2,Thick/2+0.02]) cube([Caselength-2*CaseRoundingRadius+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
mirror([ 1, 0, 0]) translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
if (CountOfMountHolderHoles>1){
translate([Caselength/2-Hole-Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([-Caselength/2+Hole+Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
if (CountOfMountHolderHoles!=2){
translate([0,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
if (MountHolderStyle==4){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference(){
union(){
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
translate([0,-MountHolderLenght+Hole*1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
if (MountHolderStyle==5){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*4+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([-Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([+Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
rotate([0,0,180]) translate([0,MountHolderLenght+CaseWidth,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([0,-MountHolderLenght+Hole*1.6+Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([0,-MountHolderLenght+Hole*1.6-Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
}
module ShowSizes () {
echo ();
echo (str(" Stable and waterproof OpenSCAD case by pbtec V6.0"));
echo ();
echo (str(" Render quality : ",$fn));
echo ();
echo (str(" --> Case outer dimensions: "));
echo (str(" Length : ",Caselength,"mm "));
echo (str(" Width : ",CaseWidth,"mm "));
echo (str(" High : ",CaseHeight,"mm "));
echo (str(" Top (upper piece) high : ",CutFromTop,"mm "));
echo (str(" Bottom (lower piece) high : ",CaseHeight-CutFromTop,"mm "));
echo (str(" Side wall thickness : ",SideWallThickness,"mm "));
echo (str(" Bottom & top wall thickness : ",BottomTopThickness,"mm "));
echo (str(" Case rounding radius : ",CaseRoundingRadius,"mm "));
echo ();
echo (str(" --> Case inner dimensions : "));
echo (str(" X : Wall to wall : ",Caselength-2*SideWallThickness,"mm "));
echo (str(" X : Screw cylinder to screw cylinder : ",Caselength-4*CaseRoundingRadius,"mm "));
echo (str(" Y : Wall to wall : ",CaseWidth-2*SideWallThickness,"mm "));
echo (str(" Y : Screw cylinder to screw cylinder : ",CaseWidth-4*CaseRoundingRadius,"mm "));
echo (str(" Top to bottom : ",CaseHeight-2*BottomTopThickness,"mm "));
echo ();
echo (str(" <b>Screw dimensions : "));
echo (str(" Metric Screw size: m",CountersinkScrew));
echo (str(" Screw hole diameter : ",ScrewHoleDia,"mm "));
echo (str(" Screw head diameter : ",ScrewHeadDia,"mm "));
echo (str(" X : Additional screw (3rd)) : ",XAdditionalScrew));
echo (str(" Y : Additional screws (3rd) : ",YAdditionalScrew));
echo (str(" --> Check if you have screws within the following size : "));
echo (str(" --> Screw m",CountersinkScrew , " max length : ",CaseHeight-BottomTopThickness, "mm"));
if(UseSquareNutInsteadOfNut) { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+SquareNutHigh, "mm")); }
else { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+NutHigh, "mm")); }
}
module GrooveStraight (length) {
color("orange") translate([length/2,0,-(GrooveDepth+AddGrooveDepthForSealing)/2]) cube([length,GrooveWidth,GrooveDepth+AddGrooveDepthForSealing],center=true);
}
module GrooveCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,-(GrooveDepth+AddGrooveDepthForSealing)]) pie(Rad+(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing, spin=0);
translate([-0.01,-0.01,-(GrooveDepth+AddGrooveDepthForSealing+0.02)]) pie(Rad-(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing+0.04, spin=0);
}
}
module RidgeStraight (length) {
color("orange") translate([length/2,0,(RidgeHeight)/2]) cube([length,RidgeWidth,RidgeHeight],center=true);
}
module RidgeCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,0]) pie(Rad+(RidgeWidth)/2, Angle, RidgeHeight, spin=0);
translate([-0.01,-0.01,-0.02]) pie(Rad-(RidgeWidth)/2, Angle, RidgeHeight+0.04, spin=0);
}
}
module BodyQuarterBottom (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference(){
union(){
color("SteelBlue")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) RidgeCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.00,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);}
}
if(UseSquareNutInsteadOfNut)
{
if (EdgeSquareNutInsertFrom_X) {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0, 0]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
if (XAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
if (YAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
}
}
module BodyQuarterTop (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference()
{
union(){
color("DarkCyan")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
translate(ScrewCornerPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
if (XAdditionalScrew){
translate(ScrewAddXPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
if (YAdditionalScrew){
translate(ScrewAddYPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) GrooveCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.07);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.057);
}
}
}
module BodyQuarter (L,W,H,Rad,Rand){
cube([L/2-Rad,W/2,BottomTopThickness],center=false); // Ground
cube([L/2,W/2-Rad,BottomTopThickness],center=false); // Ground
if (CaseRadius < CaseRoundingRadius)
{
translate([0,W/2-Rand,0]) cube([L/2-CaseRadius,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-CaseRadius,H],center=false); // Wall
translate([L/2-CaseRadius,W/2-CaseRadius,H/2]) cylinder(h=H,r=CaseRadius,center = true);
}
else
{
translate([0,W/2-Rand,0]) cube([L/2-Rad,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-Rad,H],center=false); // Wall
}
translate(ScrewCornerPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+Rand,W/2-Rad,0]) rotate([0,0, 0]) HolderGap(H,Rad,Rand); // Gap between wall and Cylinder
translate([L/2-Rad,W/2-Rad-Rand,0]) rotate([0,0,-90]) HolderGap(H,Rad,Rand); // Gap Between wall and Cylinder
if (XAdditionalScrew) {
translate(ScrewAddXPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([Rand,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
translate([Rand-2*CaseRoundingRadius,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
}
if (YAdditionalScrew) {
translate(ScrewAddYPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand+2*CaseRoundingRadius,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
}
}
module NutCut(TotalHigh,High,Dia){
AdditionalGap=0.3;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink]) cylinder($fn=6,h=High+2*AdditionalGap,d=2*sqrt(((Dia/2)*(Dia/2))+((Dia/4)*(Dia/4)))+Dia/26+2*AdditionalGap,center = true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SquareNutCut (TotalHigh,High,Size) {
AdditionalGap=0.5;
SquareNutInsertReduction= 0.2;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink])cube([Size+2*AdditionalGap,Size+2*AdditionalGap,High+2*AdditionalGap],center=true);
translate([CaseRoundingRadius/2+0.02,0,-(High+2*AdditionalGap)/2-NutSink+SquareNutInsertReduction/2]) cube([CaseRoundingRadius+0.04,Size+2*AdditionalGap,High+2*AdditionalGap-SquareNutInsertReduction],center=true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SideWallHoles () {
cylinder(h=20,d1=10,d2=15,center = true);
}
module ScrewCut(m,h,v){
// m = 3=M3 4=M4 5=M5 6=M6 usw...
// h = High of the screw inkl. head
// v = if screw head is to be sunk deeper
ScrewHeadDia=m*2; // Berechnung des Schraubenkopf Durchmessers
//ScrewCountersink=(m+8)/14-0.7; // Leichte ScrewCountersink damit Schraube nicht vorsteht
ScrewHoleDia=m+1; // ScrewHoleDiadurchmesser
translate([0,0,-0.01]) union(){ // Ganze Schraube
translate([0,0,ScrewCountersink-0.01])cylinder( h = ScrewHeadDia/4,d1=ScrewHeadDia,d2=ScrewHeadDia/2,center=false); // Kegel (Abschraegung)
translate([0,0,0]) cylinder( h = ScrewCountersink,d=ScrewHeadDia,center=false); // ScrewCountersink
translate([0,0,0.01])rotate([180,0,0])cylinder(h=v,d=ScrewHeadDia,center = false); // Versenkung
translate([0,0,0.01])cylinder( h = h,d=ScrewHoleDia,center=false); //Loch fuer Gewinde
}
}
module HolderGap (H,Rad,Rand) {
difference(){
translate([0,0,0]) cube([Rad*2-2*Rand,Rad-Rand,H],center=false);
translate([0,0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
translate([2*(Rad-Rand),0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
}
}
module DeviceHolder () {
color("yellow")translate([0,0,ScrewCylinderHeight/2+BottomTopThickness]) difference(){
cylinder(h=ScrewCylinderHeight,d=ScrewCylinderDiameter,center = true);
translate([0,0,0]) cylinder(h=ScrewCylinderHeight+0.05,d=ScrewHoleDiameter,center = true);
}
}
module pie(radius, angle, height, spin=0) {
// Negative angles shift direction of rotation
clockwise = (angle < 0) ? true : false;
// Support angles < 0 and > 360
normalized_angle = abs((angle % 360 != 0) ? angle % 360 : angle % 360 + 360);
// Select rotation direction
rotation = clockwise ? [0, 180 - normalized_angle] : [180, normalized_angle];
// Render
if (angle != 0) {
rotate([0,0,spin]) linear_extrude(height=height)
difference() {
circle(radius);
if (normalized_angle < 180) {
union() for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
else if (normalized_angle != 360) {
intersection_for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
}
}
}
module roundedBox(size, radius, sidesonly) // Laenge, Breite, Hoehe, Radius, 0/1
{
rot = [ [0,0,0], [90,0,90], [90,90,0] ];
if (sidesonly) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
else {
cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);
for (axis = [0:2]) {
for (x = [radius-size[axis]/2, -radius+size[axis]/2],
y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
rotate(rot[axis])
translate([x,y,0])
cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
}
}
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2],
z = [radius-size[2]/2, -radius+size[2]/2]) {
translate([x,y,z]) sphere(radius);
}
}
}

View file

@ -0,0 +1,838 @@
/*******************************************************************************
TITLE:
Stable and waterproof OpenSCAD case by pbtec
DESCRIPTION:
highly scalable case for 3D printing. Try it out!
Optimized for Openscad Customizer. Activate it under view/customizer and play around ;-)
No Support needed to print
- for waterproof cases you can use silicone sealing cord with diameters from 1 to 3mm
- to use also without sealing cord. The groove and ridge gives the housing a high stability and tightness.
- Use of regular nuts or square nuts
- define outer vertical radius of corners
- echo output in console shows inner and outer size and more
- echo output shows the needed length of the screws
- use screws from m2 up to m5
- default are 4 screws at each corner. For large cases add addtional ones in the middle of both x and y sides if needed
- use several predefined wall mount holder, some with multiple mounting holes (up to 3)
Important!
- If you use standard nuts you need to pause the printer a certain level to insert the nuts
- If you need a stable and waterproof case please print with 100% infill
- I'm aware that sometimes, when using too big or too small parameters, there are some rendering issues.
To prevent such issues change only one parameter at once and check the result.
for waterproofness see https://blog.prusaprinters.org/watertight-3d-printing-part-2_53638/
AUTHOR:
pbtec / pb-tec.ch
use https://paypal.me/pbtec if you want to spend me a coold beer. Thanks in advance :-)
VERSION:
V KZZ DATE COMMENT
6.0 pb 31.07.21 First Version to share
*******************************************************************************/
use <fillets3d.scad>;
/* [View settings] */
// Shows the Bottom of the case
ShowBottom = true;
// Shows the top of the case
ShowTop = true;
// Distance between top and bottom (if both are side by side displayed)
DistanceBetweenObjects = 10;
// Shows the housing assembled
ShowCaseAssembled = false;
/* [Control cuts (use only one at a time)] */
// To see the nuts inside (best view if not assembled showed)
SeeNutCut = false;
// To see the groove, ridge and Screw (best view if assembled showed)
SeeGrooveRidgeScrew = false;
/* [Case settings] */
// Length of the case
Caselength = 60;
// Width of the case
CaseWidth = 100;
// Height of the case
CaseHeight = 28;
// Splitt the Case height into bottom and top, check for the needed screws in echo output (console)
CutFromTop = 5.0;
// Thickness for the bottom and top wall (vertical walls needs to be calculated)
BottomTopThickness = 2.0;
// If this is bigger than the needed cylinder around the screw it will be ignored
CaseRadius = 12.0;
/* [Case Screw settings] */
//2=m2/2.5=m2.5/3=m3/4=m4/5=m5 // max m5, larger sizes do not fit
CountersinkScrew = 3.0; // [2:m2, 2.5: m2.5, 3: m3, 4: m4, 5: m5]
// Adds additional Screws on X axis (for large cases) --> Try it out
XAdditionalScrew = false; // can be true or false / Adds additional Screws on X axis (for large cases) --> Try it out
// Adds additional Screws on Y axis (for large cases) --> Try it out
YAdditionalScrew = false; // can be true or false / Adds additional Screws on Y axis (for large cases) --> Try it out
/* [Groove settings] */
// If using a SealingCord use the SealingCord diameter, otherwise x-times of your 3D Printer Nozzle (0.8/1.2/...) --> Ridge gets perfect for printing
GrooveWidth = 1.2; // [0.8:0.1:3]
// Not less than 1mm (for stability) and not more than 3mm --> Best 2mm
GrooveDepth = 2.0; // [1.0:0.1:3]
// Space between Groove and Ridge for a perfect fit, usualy 0.2 or 0.3 for FDM depending on your printer quality
Space = 0.3; // [0.0:0.1:0.4]
// Addtional vertical room for the pressed sealing Cord. For sealing cord 1.5mm -->0.5 // for 2mm -->0.8 // for 2.5 -->1.0 // If no sealing cord then set this parameter to 0.
AddGrooveDepthForSealing = 0.8; // [0.0:0.1:3]
// Range Inside groove/ridge. Usualy 2 times or more the printer nozzle. For best stability at least 0.8
InnerBorder = 0.8; // [0.8:0.1:4]
// Range Outside groove/ridge . Usualy 2 times or more the printer nozzle. For best stability at least 0.8
OuterBorder = 0.8; // [0.8:0.1:4]
/* [Nut general settings] */
// Size of material (plastic) above nut/square nut (3mm or more). The more, the more stable but need longer screw.
NutSink = 4.0;
/* [Standard nut settings] */
// Nut Settings / As there are (or I have) many different nuts dimensions, the size must be specified / Do not add separation space, only the real measurement // m2=1.5 // m2.5=1.9 // m3=2.4 // m4=3.2 // n5=3.8
NutHigh = 2.4;
// Distance between the paralell sides / Do not add separation space, only the real measurement // m2=3.8 // m2.5=4.9 // m3=5.4 // m4=6.9 // m5=7.9
NutDia = 5.4;
/* [Square Nut settings] */
// Select if you want to use square nuts instead of normal nuts
UseSquareNutInsteadOfNut = true;
// Select the high of the square nut / Do not add separation space, only the real measurement
SquareNutHigh = 1.9;
// Select the size of the square nut / Do not add separation space, only the real measurement
SquareNutSize = 5.4;
// Square nut insert from which side
EdgeSquareNutInsertFrom_X = true;
/* [Wall mount holder settings] */
// Select if you need a mount holder
EnableMountHolder = false;
// Chose your desired wall mount style
MountHolderStyle = 5; // [1:Style 1, 2: Style 2, 3: Style 3, 4 : Style 4, 5 : Style 5]
// Some styles (1-3) allow more than one hole
CountOfMountHolderHoles = 1; // [1:One hole centered, 2: Two holes, 3: Three holes]
MountHolderHoleDiameter = 5; // [1:0.1:10]
MountHolderThickness = 4.0; // [2:0.1:10]
/* [PCB/Device holder settings] */
// Activate customizable PCB/Device holder
ShowDeviceHolder = false;
// Hole in the cylinder for the screw // 2.9 Screw = 2mm hole
ScrewHoleDiameter = 2.6;
// The diamter of the screw cylinder
ScrewCylinderDiameter = 7;
// The height of the screw cylinders (also the deepness for the screw hole)
ScrewCylinderHeight = 8.0;
// Distance between the holders in X direction
DeviceHolder_X_Distance = 60;
// Distance between the holders in Y direction
DeviceHolder_y_Distance = 80;
// Move all holders in X direction
Offset_X = 0;
// Move all holders in Y direction
Offset_Y = -20;
/* [Wall Holes settings (for cable gland cut)] */
// Activate customizable holes for cable gland or similar
ShowSideWallHoles = false;
// Holes on X or Y side of the housing
SideWallHolesOn_X = false;
// Count of holes, if there is an additional screw on X or Y side the hole in the middle is not showed
CountOfSideWallHoles = 1; //[1:1:3]
// Diameter of the holes
SideWallHoleDiameter = 16.5; //[1:0.1:80]
// Add or decrease height position
SiedWallHoleOffset_Z = 0;
/* [Render quality settings] */
// Set to at least to 150 before render and save as .stl file, otherwise you can go down to 40 for quick 3D view
$fn = 60; // [20:1:300]
// ========================= C A L C U L A T E D S E T T I N G S (do not change!!!) ===================================
// Calculated Screw settings (do not change!!!)
ScrewHoleDia = CountersinkScrew+1;
ScrewHeadDia = CountersinkScrew*2;
ScrewCountersink = (CountersinkScrew+8)/14-0.5;
// Calculated settings for Ridge (do not change!!!)
RidgeHeight = GrooveDepth-Space;
RidgeWidth = GrooveWidth-Space;
// Calculated settings for case (do not change!!!)
SideWallThickness = InnerBorder+GrooveWidth+OuterBorder;
CaseRoundingRadius = ScrewHoleDia/2+InnerBorder+GrooveWidth+OuterBorder;
ScrewCornerPos = [Caselength/2-CaseRoundingRadius,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddXPos = [0,CaseWidth/2-CaseRoundingRadius,0];
ScrewAddYPos = [Caselength/2-CaseRoundingRadius,0,0];
// Calculated settings for wall mount holder
MountHolderLenght = MountHolderHoleDiameter*3;
// if both objects showed
X_ObjectPosition = ((ShowBottom)&&(ShowTop)&&(!ShowCaseAssembled)) ? Caselength/2+DistanceBetweenObjects/2:0;
// If the case is assembled showed
Y_TopRotation = ShowCaseAssembled ? 180:0;
Z_TopHigh = ShowCaseAssembled ? CaseHeight:0;
ShowSizes(); // Show the calculated sizes
//===============================================================================
// M A I N
//===============================================================================
/*
translate([X_ObjectPosition,0,0]) rotate([0,0,0]) difference(){
RoundCaselength=Caselength+0.1;
RoundCaseWidth=CaseWidth+0.1;
RoundCaseRadius=CaseRadius*0.8;
shellthickness=5;
casebottomradius=3;
difference(){
translate([0,0,casebottomradius/2]) cube([RoundCaselength+2*shellthickness,RoundCaseWidth+2*shellthickness,casebottomradius+shellthickness],center=true);
{
topBottomFillet(t=CaseHeight,b=0, r=casebottomradius, s=10)
minkowski()
{
translate([0,0,CaseHeight/2]) cube([RoundCaselength-RoundCaseRadius,RoundCaseWidth-RoundCaseRadius,CaseHeight],center=true);
cylinder(r=RoundCaseRadius/2,h=1);
}
}
}
}*/
// Button Bar
translate([X_ObjectPosition+21.5,0,0]) rotate([0,0,0])
{
translate([-7.5,0,20/2+0.1]) cube([11,CaseWidth-2.9*2,5], center=true);
}
// --> Show the bottom of the case
translate([X_ObjectPosition,0,0]) rotate([0,0,0])
//topBottomFillet(t=CaseHeight,b=0, r=3, s=15)
difference(){
union(){
BodyBottom();
// **** Add your bottom case additions here ****
//cylinder(h=20,d=15,center = true); // Example
//#translate([-18,0,18/2+2]) rotate([90,0,0]) cylinder(h=70,d=18,center=true); //battery mockup
translate([-7.5,0,20/2+0.1]) cube([2,CaseWidth-4,20],center=true); //battery divider
translate([-18,CaseWidth/2-12, 20/2+0.1]) cube([20,4,20],center=true); //battery ends
translate([-18,-(CaseWidth/2-12),20/2+0.1]) cube([20,4,20],center=true); //battery ends
translate([0,10,16/2+BottomTopThickness]) cube([6,26+4,16],center=true); //wemos walls
translate([20.75,10,16/2+BottomTopThickness]) cube([6,26+4,16],center=true); //wemos walls
translate([-7.5+2+1,-(CaseWidth/2-31/2-0.1),15/2+0.1]) cube([5,31,15],center=true); //charge board wall
ButtonSides(14,-(15+2)*2);
ButtonSides(14,-(15+2)*1);
//ButtonSides(14,0);
//ButtonSides(14,(15+2)*1);
ButtonSides(14,(15+2)*2);
}
// **** Add your bottom case cuts here ****
//cylinder(h=15,d=20,center = true); // Example
ButtonCut(14,-(15+2)*2);
ButtonCut(14,-(15+2)*1);
//ButtonCut(14,0);
//ButtonCut(14,(15+2)*1);
ButtonCut(14,(15+2)*2);
translate([0,-14,-4+13]) {
//#translate([20,0,10]) cube([15,14,8],center=true); //switch case mockup
translate([20,0,10]) rotate([0,90,0]) cylinder(h=20,d=6); //on off switch
translate([27,6.5,10]) cube([2,2,2],center=true); //on off switch notch
}
translate([10-0.1,10,18/2+BottomTopThickness+0.1]) cube([34.5,26,18.1],center=true); //wemos
translate([-7.5+2,-(CaseWidth/2-28/2-0.5),17.5/2+BottomTopThickness+0.1]) cube([1.5,28,17.5],center=true); //charge board pcb
translate([-7.5+2.5,-(CaseWidth/2-4/2+0.1),17.5/2+BottomTopThickness+0.1]) cube([5,4,10],center=true); //charge board usb
translate([-7.5+2.5+0.01,-(CaseWidth/2-40/2-3),17.5/2+BottomTopThickness+0.1]) cube([3,40,17.5],center=true); //charge board
}
// --> Show the top of the case
translate([-X_ObjectPosition,0,Z_TopHigh+0.03]) rotate([0,Y_TopRotation,0]) difference(){
union(){
BodyTop();
// **** Add your bottom top additions here ****
//cylinder(h=18,d=10,center = true); // Example
}
// **** Add your top case cuts here ****
//cylinder(h=20,d=5,center = true); // Example
}
//===============================================================================
// M O D U L E S
//===============================================================================
module ButtonCut(xpos,ypos) {
translate([xpos,ypos,17/2+BottomTopThickness+0.39])
{
cube([15.5,15,17],center=true);//key
translate([0,0,-17/2-2.5]) cylinder(d=10.5,h=5);
translate([0,0,-17/2-2.5+5/2+0.5]) rotate([0,0,45]) cube([5,14,5],center=true);
}
}
module ButtonSides (xpos,ypos) {
translate([xpos,ypos,17/2+2.5-0.1])
{
translate([0,0,-7+BottomTopThickness-0.1]) cube([15.5+2*2,15+2*2,7],center=true);//key
}
}
module BodyBottom () {
if(ShowBottom)
{
difference(){
union()
{
rotate([ 0, 0, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterBottom(Caselength,CaseWidth,CaseHeight-CutFromTop,CaseRoundingRadius,SideWallThickness);
if (EnableMountHolder)
{
color("SteelBlue")
if (MountHolderStyle!=5)
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
rotate([0,0,180]) translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
else
{
translate([0,CaseWidth/2,0]) MountHolder(MountHolderThickness,MountHolderHoleDiameter);
}
}
if (ShowDeviceHolder)
{
translate([DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([DeviceHolder_X_Distance/2+Offset_X,-DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
translate([-DeviceHolder_X_Distance/2+Offset_X,DeviceHolder_y_Distance/2+Offset_Y,-0.01]) DeviceHolder();
}
}
if (SeeNutCut) { color("red") translate([0,0,CaseHeight/2+CaseHeight-CutFromTop-NutSink]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight],center=true);}
if (SeeGrooveRidgeScrew) { color("red") translate([CaseRoundingRadius+50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth*2+0.1,CaseHeight+0.1],center=true);}
if (ShowSideWallHoles)
{
color("Yellow")
if(SideWallHolesOn_X)
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!XAdditionalScrew))
{
translate([0,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(XAdditionalScrew))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/4-CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([-Caselength/4+CaseRoundingRadius/2,CaseWidth/2-SideWallThickness/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,0]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
else
{
if ((CountOfSideWallHoles==1)||(CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
if ((CountOfSideWallHoles==1)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==3)&&(!YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,0,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
if ((CountOfSideWallHoles==1)&&(YAdditionalScrew))
{
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
if ((CountOfSideWallHoles==2)||(CountOfSideWallHoles==3))
{
translate([Caselength/2-SideWallThickness/2,CaseWidth/4-CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
translate([Caselength/2-SideWallThickness/2,-CaseWidth/4+CaseRoundingRadius/2,SiedWallHoleOffset_Z+ BottomTopThickness+(CaseHeight-CutFromTop-BottomTopThickness)/2 ]) rotate([90,0,90]) cylinder(h=SideWallThickness+0.04,d=SideWallHoleDiameter,center = true);
}
}
}
}
}
}
module BodyTop () {
if (ShowTop)
{
difference(){
union(){
rotate([ 0, 0, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
rotate([ 0, 0,180]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 0, 1, 0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
mirror([ 1, 0 ,0]) BodyQuarterTop(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
if (SeeGrooveRidgeScrew) { color("red") translate([-CaseRoundingRadius-50,0,(CaseHeight+0.1)/2-0.05]) cube([Caselength+0.1,CaseWidth+0.1,CaseHeight+0.1],center=true);}
}
}
}
module MountHolder (Thick,Hole) {
translate([0,0,0.005]) difference(){
if (MountHolderStyle==1){
$fn=40;
roundedBox([Caselength, MountHolderLenght*2, Thick*2], Thick/3, 0);
}
if (MountHolderStyle==2){
$fn=60;
roundedBox([Caselength, MountHolderLenght*2, Thick*2],CaseRoundingRadius , 1);
}
if (MountHolderStyle==3){
roundedBox([Caselength, MountHolderLenght*2, Thick*2],0 , 2);
}
if((MountHolderStyle>0)&&(MountHolderStyle<4)){
translate([0,0,-Thick/2-0.02]) cube([Caselength+0.02,MountHolderLenght*2+0.02,Thick+0.04],center=true);
translate([0,-MountHolderLenght/2-CaseRoundingRadius,Thick/2+0.02]) cube([Caselength+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-MountHolderLenght/2,Thick/2+0.02]) cube([Caselength-2*CaseRoundingRadius+0.02,MountHolderLenght+0.02,Thick+0.08],center=true);
translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
mirror([ 1, 0, 0]) translate([0,-CaseRoundingRadius,MountHolderThickness/2-0.02]) translate(ScrewAddYPos) cylinder(h=MountHolderThickness+0.06,d=ScrewHoleDia,center = true);
if (CountOfMountHolderHoles>1){
translate([Caselength/2-Hole-Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([-Caselength/2+Hole+Thick/3,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
if (CountOfMountHolderHoles!=2){
translate([0,Hole*1.5,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
if (MountHolderStyle==4){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference(){
union(){
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
translate([0,-MountHolderLenght+Hole*1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
if (MountHolderStyle==5){
HolderRad=Hole/2;
HolderWidth=4*Hole;
translate([0,MountHolderLenght,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*4+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([-Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([+Hole/1.1,-MountHolderLenght+Hole*1.6,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
rotate([0,0,180]) translate([0,MountHolderLenght+CaseWidth,0]) difference()
{
union(){
$fn=40;
translate([0,-MountHolderLenght+HolderRad,0]) roundedBox([HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([-HolderWidth/2+HolderRad,0,0]) rotate([0,0,-45]) translate([HolderWidth-HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
translate([ HolderWidth/2-HolderRad,0,0]) rotate([0,0,45]) translate([-HolderWidth+HolderRad,-MountHolderLenght+HolderRad,0]) roundedBox([2*HolderWidth, MountHolderLenght*2, Thick*2],HolderRad , 0);
}
translate([0,-(3*HolderWidth)/2-MountHolderLenght,-0.02]) cube([10*HolderWidth,3*HolderWidth,Thick*2+0.06],center=true);
translate([0,-(3*HolderWidth)/2,-Thick-0.02]) cube([4*HolderWidth,4*HolderWidth,Thick*2],center=true);
hull(){
translate([0,-MountHolderLenght+Hole*1.6+Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
translate([0,-MountHolderLenght+Hole*1.6-Hole/1.8,MountHolderThickness/2-0.02]) cylinder(h=MountHolderThickness+0.06,d=Hole,center = true);
}
}
}
}
module ShowSizes () {
echo ();
echo (str(" Stable and waterproof OpenSCAD case by pbtec V6.0"));
echo ();
echo (str(" Render quality : ",$fn));
echo ();
echo (str(" --> Case outer dimensions: "));
echo (str(" Length : ",Caselength,"mm "));
echo (str(" Width : ",CaseWidth,"mm "));
echo (str(" High : ",CaseHeight,"mm "));
echo (str(" Top (upper piece) high : ",CutFromTop,"mm "));
echo (str(" Bottom (lower piece) high : ",CaseHeight-CutFromTop,"mm "));
echo (str(" Side wall thickness : ",SideWallThickness,"mm "));
echo (str(" Bottom & top wall thickness : ",BottomTopThickness,"mm "));
echo (str(" Case rounding radius : ",CaseRoundingRadius,"mm "));
echo ();
echo (str(" --> Case inner dimensions : "));
echo (str(" X : Wall to wall : ",Caselength-2*SideWallThickness,"mm "));
echo (str(" X : Screw cylinder to screw cylinder : ",Caselength-4*CaseRoundingRadius,"mm "));
echo (str(" Y : Wall to wall : ",CaseWidth-2*SideWallThickness,"mm "));
echo (str(" Y : Screw cylinder to screw cylinder : ",CaseWidth-4*CaseRoundingRadius,"mm "));
echo (str(" Top to bottom : ",CaseHeight-2*BottomTopThickness,"mm "));
echo ();
echo (str(" <b>Screw dimensions : "));
echo (str(" Metric Screw size: m",CountersinkScrew));
echo (str(" Screw hole diameter : ",ScrewHoleDia,"mm "));
echo (str(" Screw head diameter : ",ScrewHeadDia,"mm "));
echo (str(" X : Additional screw (3rd)) : ",XAdditionalScrew));
echo (str(" Y : Additional screws (3rd) : ",YAdditionalScrew));
echo (str(" --> Check if you have screws within the following size : "));
echo (str(" --> Screw m",CountersinkScrew , " max length : ",CaseHeight-BottomTopThickness, "mm"));
if(UseSquareNutInsteadOfNut) { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+SquareNutHigh, "mm")); }
else { echo (str(" --> Screw m",CountersinkScrew , " min length : ",CutFromTop+NutSink+NutHigh, "mm")); }
}
module GrooveStraight (length) {
color("orange") translate([length/2,0,-(GrooveDepth+AddGrooveDepthForSealing)/2]) cube([length,GrooveWidth,GrooveDepth+AddGrooveDepthForSealing],center=true);
}
module GrooveCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,-(GrooveDepth+AddGrooveDepthForSealing)]) pie(Rad+(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing, spin=0);
translate([-0.01,-0.01,-(GrooveDepth+AddGrooveDepthForSealing+0.02)]) pie(Rad-(GrooveWidth)/2, Angle, GrooveDepth+AddGrooveDepthForSealing+0.04, spin=0);
}
}
module RidgeStraight (length) {
color("orange") translate([length/2,0,(RidgeHeight)/2]) cube([length,RidgeWidth,RidgeHeight],center=true);
}
module RidgeCurved (Angle,Rad) {
color("orange") difference(){
translate([0,0,0]) pie(Rad+(RidgeWidth)/2, Angle, RidgeHeight, spin=0);
translate([-0.01,-0.01,-0.02]) pie(Rad-(RidgeWidth)/2, Angle, RidgeHeight+0.04, spin=0);
}
}
module BodyQuarterBottom (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference(){
union(){
color("SteelBlue")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) RidgeCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.00,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) RidgeStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) RidgeCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) RidgeCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) RidgeStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.05);}
}
if(UseSquareNutInsteadOfNut)
{
if (EdgeSquareNutInsertFrom_X) {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0, 0]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
}
else {translate(ScrewCornerPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
if (XAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) rotate([0,0,90]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddXPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
if (YAdditionalScrew){
if(UseSquareNutInsteadOfNut) {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) SquareNutCut(CutFromTop,SquareNutHigh,SquareNutSize);}
else {translate(ScrewAddYPos) translate([0,0,CutFromTop+0.01]) NutCut(CutFromTop,NutHigh,NutDia);}
}
}
}
module BodyQuarterTop (Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness) {
difference()
{
union(){
color("DarkCyan")BodyQuarter(Caselength,CaseWidth,CutFromTop,CaseRoundingRadius,SideWallThickness);
}
translate(ScrewCornerPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
if (XAdditionalScrew){
translate(ScrewAddXPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
if (YAdditionalScrew){
translate(ScrewAddYPos) ScrewCut(CountersinkScrew,CutFromTop+0.01,0);
}
translate([CaseRoundingRadius+ScrewHoleDia/2-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-3*CaseRoundingRadius-ScrewHoleDia+0.03);
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,CaseRoundingRadius+ScrewHoleDia/2-0.02,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-3*CaseRoundingRadius-ScrewHoleDia+0.04);
translate([0,0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,180]) GrooveCurved(90,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.02,-0.01,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness+0.0,CutFromTop+0.01]) translate(ScrewCornerPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
if (XAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,180]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-ScrewHoleDia-SideWallThickness+0.04,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([ScrewHoleDia+SideWallThickness,-0.01,CutFromTop+0.01]) translate(ScrewAddXPos) rotate([0,0,90]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([-0.01,CaseWidth/2-OuterBorder-GrooveWidth/2-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,0]) GrooveStraight(Caselength/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.07);
}
if (YAdditionalScrew){
translate([0,0,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,90]) GrooveCurved(180,ScrewHoleDia/2+OuterBorder+GrooveWidth/2);
translate([-0.01,-ScrewHoleDia-SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,0]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
translate([-0.01,ScrewHoleDia+SideWallThickness-0.01,CutFromTop+0.01]) translate(ScrewAddYPos) rotate([0,0,270]) GrooveCurved(90,ScrewHoleDia/2+InnerBorder+GrooveWidth/2);
}
else{
translate([Caselength/2-OuterBorder-GrooveWidth/2-0.01,-0.01,CutFromTop+0.01]) translate([0,0,0]) rotate([0,0,90]) GrooveStraight(CaseWidth/2-2*CaseRoundingRadius-ScrewHoleDia/2+0.057);
}
}
}
module BodyQuarter (L,W,H,Rad,Rand){
cube([L/2-Rad,W/2,BottomTopThickness],center=false); // Ground
cube([L/2,W/2-Rad,BottomTopThickness],center=false); // Ground
if (CaseRadius < CaseRoundingRadius)
{
translate([0,W/2-Rand,0]) cube([L/2-CaseRadius,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-CaseRadius,H],center=false); // Wall
translate([L/2-CaseRadius,W/2-CaseRadius,H/2]) cylinder(h=H,r=CaseRadius,center = true);
}
else
{
translate([0,W/2-Rand,0]) cube([L/2-Rad,Rand,H],center=false); // Wall
translate([L/2-Rand,0,0]) cube([Rand,W/2-Rad,H],center=false); // Wall
}
translate(ScrewCornerPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+Rand,W/2-Rad,0]) rotate([0,0, 0]) HolderGap(H,Rad,Rand); // Gap between wall and Cylinder
translate([L/2-Rad,W/2-Rad-Rand,0]) rotate([0,0,-90]) HolderGap(H,Rad,Rand); // Gap Between wall and Cylinder
if (XAdditionalScrew) {
translate(ScrewAddXPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([Rand,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
translate([Rand-2*CaseRoundingRadius,W/2-Rad,0]) rotate([0,0,0]) HolderGap(H,Rad,Rand);
}
if (YAdditionalScrew) {
translate(ScrewAddYPos) cylinder(h=H,r=Rad,center = false); // Cylinder
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand+2*CaseRoundingRadius,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
translate([L/2-3*Rad+2*CaseRoundingRadius,-Rand,0]) rotate([0,0, 270]) HolderGap(H,Rad,Rand);
}
}
module NutCut(TotalHigh,High,Dia){
AdditionalGap=0.3;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink]) cylinder($fn=6,h=High+2*AdditionalGap,d=2*sqrt(((Dia/2)*(Dia/2))+((Dia/4)*(Dia/4)))+Dia/26+2*AdditionalGap,center = true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SquareNutCut (TotalHigh,High,Size) {
AdditionalGap=0.5;
SquareNutInsertReduction= 0.2;
translate([0,0,-(High+2*AdditionalGap)/2-NutSink])cube([Size+2*AdditionalGap,Size+2*AdditionalGap,High+2*AdditionalGap],center=true);
translate([CaseRoundingRadius/2+0.02,0,-(High+2*AdditionalGap)/2-NutSink+SquareNutInsertReduction/2]) cube([CaseRoundingRadius+0.04,Size+2*AdditionalGap,High+2*AdditionalGap-SquareNutInsertReduction],center=true);
translate([0,0,-(TotalHigh-SideWallThickness)/2]) cylinder(h=TotalHigh-SideWallThickness,d=ScrewHoleDia,center = true);
}
module SideWallHoles () {
cylinder(h=20,d1=10,d2=15,center = true);
}
module ScrewCut(m,h,v){
// m = 3=M3 4=M4 5=M5 6=M6 usw...
// h = High of the screw inkl. head
// v = if screw head is to be sunk deeper
ScrewHeadDia=m*2; // Berechnung des Schraubenkopf Durchmessers
//ScrewCountersink=(m+8)/14-0.7; // Leichte ScrewCountersink damit Schraube nicht vorsteht
ScrewHoleDia=m+1; // ScrewHoleDiadurchmesser
translate([0,0,-0.01]) union(){ // Ganze Schraube
translate([0,0,ScrewCountersink-0.01])cylinder( h = ScrewHeadDia/4,d1=ScrewHeadDia,d2=ScrewHeadDia/2,center=false); // Kegel (Abschraegung)
translate([0,0,0]) cylinder( h = ScrewCountersink,d=ScrewHeadDia,center=false); // ScrewCountersink
translate([0,0,0.01])rotate([180,0,0])cylinder(h=v,d=ScrewHeadDia,center = false); // Versenkung
translate([0,0,0.01])cylinder( h = h,d=ScrewHoleDia,center=false); //Loch fuer Gewinde
}
}
module HolderGap (H,Rad,Rand) {
difference(){
translate([0,0,0]) cube([Rad*2-2*Rand,Rad-Rand,H],center=false);
translate([0,0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
translate([2*(Rad-Rand),0,-0.02]) cylinder(h=H+0.04,r=Rad-Rand,center = false);
}
}
module DeviceHolder () {
color("yellow")translate([0,0,ScrewCylinderHeight/2+BottomTopThickness]) difference(){
cylinder(h=ScrewCylinderHeight,d=ScrewCylinderDiameter,center = true);
translate([0,0,0]) cylinder(h=ScrewCylinderHeight+0.05,d=ScrewHoleDiameter,center = true);
}
}
module pie(radius, angle, height, spin=0) {
// Negative angles shift direction of rotation
clockwise = (angle < 0) ? true : false;
// Support angles < 0 and > 360
normalized_angle = abs((angle % 360 != 0) ? angle % 360 : angle % 360 + 360);
// Select rotation direction
rotation = clockwise ? [0, 180 - normalized_angle] : [180, normalized_angle];
// Render
if (angle != 0) {
rotate([0,0,spin]) linear_extrude(height=height)
difference() {
circle(radius);
if (normalized_angle < 180) {
union() for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
else if (normalized_angle != 360) {
intersection_for(a = rotation)
rotate(a) translate([-radius, 0, 0]) square(radius * 2);
}
}
}
}
module roundedBox(size, radius, sidesonly) // Laenge, Breite, Hoehe, Radius, 0/1
{
rot = [ [0,0,0], [90,0,90], [90,90,0] ];
if (sidesonly) {
cube(size - [2*radius,0,0], true);
cube(size - [0,2*radius,0], true);
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2]) {
translate([x,y,0]) cylinder(r=radius, h=size[2], center=true);
}
}
else {
cube([size[0], size[1]-radius*2, size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1], size[2]-radius*2], center=true);
cube([size[0]-radius*2, size[1]-radius*2, size[2]], center=true);
for (axis = [0:2]) {
for (x = [radius-size[axis]/2, -radius+size[axis]/2],
y = [radius-size[(axis+1)%3]/2, -radius+size[(axis+1)%3]/2]) {
rotate(rot[axis])
translate([x,y,0])
cylinder(h=size[(axis+2)%3]-2*radius, r=radius, center=true);
}
}
for (x = [radius-size[0]/2, -radius+size[0]/2],
y = [radius-size[1]/2, -radius+size[1]/2],
z = [radius-size[2]/2, -radius+size[2]/2]) {
translate([x,y,z]) sphere(radius);
}
}
}

54
cad/fillets2d.scad.txt Normal file
View file

@ -0,0 +1,54 @@
/*
Modified by Kevin Gravier
https://www.thingiverse.com/mrkmg/about
Originally from: https://github.com/OskarLinde/scad-utils/blob/master/morphology.scad
Modules:
rounding2d(r)
r = radius of rounding
fillet2d(r)
r = radius of rounding
*/
$fa = 0.1;
$fs = 0.1;
// Example
linear_extrude(1)
rounding2d(1)
fillet2d(1)
difference() {
union() {
square([10, 10], center = true);
translate([5, 5])
square([10, 10], center = true);
}
translate([-5, -5])
square([10, 10], center = true);
translate([8, 8])
circle(3);
}
// Example, text
translate([-20, -15])
rotate([0, 0, 0])
linear_extrude(1)
rounding2d(.25)
fillet2d(.25)
text("Fillets!");
module fillet2d(r) {
offset(r = -r) offset(delta = r) children(0);
}
module rounding2d(r) {
offset(r = r) offset(delta = -r) children(0);
}

162
cad/fillets3d.scad Normal file
View file

@ -0,0 +1,162 @@
/*
Created by Kevin Gravier
https://www.thingiverse.com/mrkmg/about
My take on a top and bottom fillet for a 3d shape.
Available Modules:
topBottomFillet(b, t, r, s, e)
b = z of bottom of 3d object
t = z of top of 3d object
r = radius of fillet
s = steps of filler (smaller is smoother)
e = enabled (pass e = 0 to disable fillet for faster preview)
topFillet(t, r, s, e)
t = z of top of 3d object
r = radius of fillet
s = steps of filler (smaller is smoother)
e = enabled (pass e = 0 to disable fillet for faster preview)
bottomFillet(b, r, s, e)
b = z of bottom of 3d object
r = radius of fillet
s = steps of filler (smaller is smoother)
e = enabled (pass e = 0 to disable fillet for faster preview)
*/
enable = 1;
// Example, hard edges
translate([0, 20, 0])
topBottomFillet(b = 0, t = 10, r = 2, s = 20, e = enable)
linear_extrude(10, scale = 1.2)
difference() {
union() {
square([10, 10], true);
translate([-15, 0]) circle(15);
}
translate([-15, 0]) circle(8);
translate([-15, 0]) square([13, 13], center = true);
}
// Example, soft edges
use <fillets2d.scad>;
translate([0, -20, 0])
topBottomFillet(b = 0, t = 10, r = 1, s = 10, e = enable)
linear_extrude(10)
rounding2d(1)
fillet2d(1)
difference() {
union() {
square([10, 10], true);
translate([-15, 0]) circle(15);
}
translate([-15, 0]) circle(8);
translate([-15, 0]) square([13, 13], center = true);
}
// Example, text
translate([-60, 40])
rotate([0, 0, -90])
topBottomFillet(b = 0, t = 3, r = .5, s = 5, e = enable)
linear_extrude(3)
text("Fillets!", size = 20);
// Library
function filletDepth(r, d, i) = r * cos(asin(d * i / r));
module topBottomFillet(b = 0, t = 2, r = 1, s = 4, e = 1) {
if (e == 1) {
topFilletPeice(t = t, r = r, s = s) children(0);
bottomFilletPeice(b = b, r = r, s = s) children(0);
render()
difference() {
children(0);
translate([0, 0, t - r])
linear_extrude(r + 1)
offset(delta = 1e5)
projection()
children(0);
translate([0, 0, b - 1])
linear_extrude(r + 1)
offset(delta = 1e5)
projection()
children(0);
}
}
if (e == 0) children(0);
}
module topFillet(t = 2, r = 1, s = 4, e = 1) {
if (e == 1) {
topFilletPeice(t = t, r = r, s = s) children(0);
render()
difference() {
children(0);
translate([0, 0, t-r])
linear_extrude(r + 1)
offset(delta = 1e5)
projection()
children(0);
}
}
if (e == 0) children(0);
}
module bottomFillet(b = 0, r = 1, s = 4, e = 1) {
if (e == 1) {
bottomFilletPeice(b = b, r = r, s = s) children(0);
render()
difference() {
children(0);
translate([0, 0, b - r - 1])
linear_extrude(r + 1)
offset(delta = 1e5)
projection()
children(0);
}
}
if (e == 0) children(0);
}
module topFilletPeice(t = 2, r = 1, s = 4) {
d = r/s;
for (i = [0:s]) {
x = filletDepth(r, d, i);
z = d * (s - i + 1);
translate([0, 0, t - z])
linear_extrude(d)
offset(delta = -r + x)
projection(true)
translate([0, 0, -t + z])
children(0);
}
}
module bottomFilletPeice(b = 0, r =1, s = 4) {
d = r/s;
for (i = [0:s]) {
x = filletDepth(r, d, i);
z = d * (s - i);
translate([0, 0, b + z])
linear_extrude(d)
offset(delta = -r + x)
projection(true)
translate([0, 0, b - z])
children(0);
}
}

Binary file not shown.

BIN
cad/keycap.FCStd Normal file

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,92 @@
import signal
import sys
import socket
#import time
from pykeyboard import PyKeyboard #pip install pyuserinput
#for windows also pip install pywin32
import vgamepad as vg #pip install vgamepad https://pypi.org/project/vgamepad/
gamepads = [vg.VX360Gamepad(),vg.VX360Gamepad()]
keyboard = PyKeyboard()
UDP_IP = "0.0.0.0"
UDP_PORT = 5005
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
#for gamepad: "gp0A" for gamepad 0 button A
#each entry corresponds to consecutive ids
keys=[\
['a','d','w','s','q','e'],\
['j','l','i','k','u','o'],\
['f','h','t','g','r','z'],\
['b','n','m',',','.','-'],\
["gp0L","gp0R","gp0U","gp0D","gp0A","gp0B",]\
]
try:
while True:
data, (recip,recport) = sock.recvfrom(1024) # buffer size is 1024 bytes
print("received message: %s" % data)
id=data[0]
action=data[1]
input=data[2]
print(" ip=%s port=%s" % (recip,recport))
print(" ID=%s" % id)
print(" Action=%s" % action)
print(" Input=%s" % input)
print()
if action==1: #press
key=keys[id][input]
print(" Press Key=%s" % key)
if len(key)==1:
keyboard.press_key(key)
elif key.startswith("gp"):
gpid=int(key[2])
if key[3]=='L':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_LEFT)
if key[3]=='R':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_RIGHT)
if key[3]=='U':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_UP)
if key[3]=='D':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_DOWN)
if key[3]=='A':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_A)
if key[3]=='B':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_B)
if key[3]=='S':
gamepads[gpid].press_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_START)
gamepads[gpid].update()
elif action==2: #release
key=keys[id][input]
print(" Release Key=%s" % key)
if len(key)==1:
keyboard.release_key(key)
elif key.startswith("gp"):
gpid=int(key[2])
if key[3]=='L':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_LEFT)
if key[3]=='R':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_RIGHT)
if key[3]=='U':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_UP)
if key[3]=='D':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_DPAD_DOWN)
if key[3]=='A':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_A)
if key[3]=='B':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_B)
if key[3]=='S':
gamepads[gpid].release_button(button=vg.XUSB_BUTTON.XUSB_GAMEPAD_START)
gamepads[gpid].update()
except KeyboardInterrupt:
print("Ctrl-C pressed!")
sys.exit(0)

View file

@ -0,0 +1,3 @@
pyuserinput
pywin32
vgamepad

39
include/README Normal file
View file

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View file

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

28
platformio.ini Normal file
View file

@ -0,0 +1,28 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:d1_mini]
platform = espressif8266
board = d1_mini
framework = arduino
upload_speed = 921600
monitor_speed = 115200
build_flags =
-D ID=0 ;0=black box first print, 1=black print new design, 2=white cardboard
-D PIN_LEFT=D5
-D PIN_RIGHT=D6
-D PIN_UP=D2 ;SDA
-D PIN_DOWN=D1 ;SCL
-D PIN_A=D4 ;D3 GPIO 0, wakes esp from deepsleep when pulled down
-D PIN_B=D3 ;D3 GPIO 0, prevents boot when pulled down

163
src/main.cpp Normal file
View file

@ -0,0 +1,163 @@
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "network";
const char* password = "password";
WiFiUDP Udp;
unsigned int localUdpPort = 4210; // local port to listen on
char incomingPacket[255]; // buffer for incoming packets
//char replyPacket[] = "Hi there! Got the message :-)"; // a reply string to send back
unsigned int remoteUDPPort = 5005;
IPAddress remoteIP = IPAddress(192,168,1,221);
bool flag_init_send;
enum Action {
HELLO=0,
PRESS=1,
RELEASE=2,
DOWN=3,
UP=4
};
#define INPUT_SIZE 6
enum Input {
KEY_LEFT=0,
KEY_RIGHT=1,
KEY_UP=2,
KEY_DOWN=3,
KEY_A=4,
KEY_B=5
};
uint8_t input_pins[] = {PIN_LEFT,PIN_RIGHT,PIN_UP,PIN_DOWN,PIN_A,PIN_B};
bool sent_states[INPUT_SIZE];
bool input_states[INPUT_SIZE];
unsigned long last_send_state[INPUT_SIZE];
#define DEBOUNCE_TIME 50
typedef struct struct_message {
uint8_t id;
Action action;
Input input;
} struct_message;
struct_message myData;
bool flag_send=false;
void setup()
{
Serial.begin(115200);
Serial.println();
for (uint8_t i=0;i<INPUT_SIZE;i++)
{
pinMode(input_pins[i],INPUT_PULLUP);
}
myData.id=ID;
myData.action=HELLO;
myData.input=KEY_LEFT; //does not matter
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
flag_init_send=true;
Udp.begin(localUdpPort);
Serial.printf("Now listening at IP %s, UDP port %d\n", WiFi.localIP().toString().c_str(), localUdpPort);
}
void loop()
{
unsigned long loopmillis=millis();
int packetSize = Udp.parsePacket();
if (packetSize)
{
// receive incoming UDP packets
Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(incomingPacket, 255);
if (len > 0)
{
incomingPacket[len] = 0;
}
Serial.printf("UDP packet contents: %s\n", incomingPacket);
}
for (uint8_t i=0;i<INPUT_SIZE;i++)
{
input_states[i]=!digitalRead(input_pins[i]);
//input_states High=Pressed
}
for (uint8_t i=0;i<INPUT_SIZE;i++)
{
if (input_states[i]!=sent_states[i] && loopmillis-last_send_state[i]>DEBOUNCE_TIME) //input changed
{
last_send_state[i]=loopmillis;
if (input_states[i]){
myData.action=PRESS;
}else{
myData.action=RELEASE;
}
myData.input=Input(i);
flag_send=true;
}
}
#define TIME_IDLE_SEND 60000 //ms. 0 disables
static unsigned long last_idlesend=0;
if (((millis()-last_idlesend > TIME_IDLE_SEND && TIME_IDLE_SEND!=0) || (flag_init_send)) && !flag_send){
last_idlesend=millis();
flag_init_send=false;
myData.action=HELLO;
flag_send=true;
}
if (flag_send) {
flag_send=false;
Udp.beginPacket(remoteIP, remoteUDPPort);
char packet[3];
packet[0]=myData.id;
packet[1]=myData.action;
packet[2]=myData.input;
if (myData.action==PRESS){
sent_states[myData.input]=true;
}else if (myData.action==RELEASE){
sent_states[myData.input]=false;
}
Serial.printf("sending %i %i %i\n",packet[0],packet[1],packet[2]);
Udp.write(packet,sizeof(packet));
Udp.endPacket();
}
}

11
test/README Normal file
View file

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html