%classpath config resolver maven-public https://software.pschatzmann.ch/repository/maven-public/
%classpath add mvn ch.pschatzmann:scad4j:0.0.1-SNAPSHOT
Added new repo: maven-public
All classes that we will use are in the module ch.pschatzmann.scad4j. So we import all classes:
import ch.pschatzmann.scad4j._
import ch.pschatzmann.scad4j._
We will use the locally installed openscad as renderer and display the result with simple 2D graphincs
SCAD.setFormatter(new ch.pschatzmann.scad4j.format.OpenSCADFormatter())
SCAD.setDisplay3D(false)
var model = new SCAD()
scad4j V0.1
We will base our design of a single motor section on a hollow cylinder
model.addParameter("motorDiameter",8.6)
.addParameter("heightMotor",6)
.addParameter("pinHeight",10)
.addParameter("outerRingDiameter",75)
.addParameter("quadHeight",3)
.addParameter("quadWidth",1)
.addParameter("$fn",80)
var motorRing = model.difference(
model.cylinder().height("quadHeight").diameter("outerRingDiameter").center(),
model.cylinder().height("quadHeight*2").diameter("outerRingDiameter-(quadWidth*2)").center()
).toModule("motorRing")
motorRing.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 2 elements
The motor will me mounted on a inner cylinder
var motorInnerRing = model.cylinder().height("heightMotor").diameter("motorDiameter").center
.translate.values("0","0","-(quadHeight/2)").toModule("motorInnerRing")
motorInnerRing.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 1 elements
We add the two rings and generate some spikes with the help of rotated cubes
var motorBase = model.union(
motorRing,
motorInnerRing,
model.cube().size("outerRingDiameter","quadWidth","quadHeight").center,
model.cube().size("outerRingDiameter","quadWidth","quadHeight").center
.rotate.values(0,0,45),
model.cube().size("quadWidth","outerRingDiameter","quadHeight").center,
model.cube().size("quadWidth","outerRingDiameter","quadHeight").center
.rotate.values(0,0,45)
).toModule("motorBase")
motorBase.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 7 elements
Now we cut a hole in the center
var motor = model.difference(
motorBase,
model.cylinder().height("heightMotor*3").diameter("motorDiameter-(quadWidth*3)").center
).toModule("motor")
motor.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 13 elements
We are almost done - we just copy the motor into the 4 corners
var quad = model.group (
model.command("motorDistance = outerRingDiameter/2;"),
model.ref("motor").translate.values("motorDistance","motorDistance","0"),
model.ref("motor").translate.values("-motorDistance","-motorDistance","0"),
model.ref("motor").translate.values("motorDistance","-motorDistance","0"),
model.ref("motor").translate.values("-motorDistance","motorDistance","0")
).toModule("quad")
quad.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 52 elements
Finally we can display the generated OpenSCAD source code:
quad
$fn = 80; heightMotor = 6; motorDiameter = 8.6; outerRingDiameter = 75; pinHeight = 10; quadHeight = 3; quadWidth = 1; module motor() { difference() { motorBase(); cylinder(h=heightMotor*3,d=motorDiameter-(quadWidth*3),center=true); } } module motorBase() { union() { motorRing(); motorInnerRing(); cube([outerRingDiameter,quadWidth,quadHeight],center=true); rotate(a=[0,0,45]) cube([outerRingDiameter,quadWidth,quadHeight],center=true); cube([quadWidth,outerRingDiameter,quadHeight],center=true); rotate(a=[0,0,45]) cube([quadWidth,outerRingDiameter,quadHeight],center=true); } } module motorInnerRing() { translate([0,0,-(quadHeight/2)]) cylinder(h=heightMotor,d=motorDiameter,center=true); } module motorRing() { difference() { cylinder(h=quadHeight,d=outerRingDiameter,center=true); cylinder(h=quadHeight*2,d=outerRingDiameter-(quadWidth*2),center=true); } } module quad() { { motorDistance = outerRingDiameter/2; translate([motorDistance,motorDistance,0]) motor(); translate([-motorDistance,-motorDistance,0]) motor(); translate([motorDistance,-motorDistance,0]) motor(); translate([-motorDistance,motorDistance,0]) motor(); } } quad();
The motor holder will mount the motor and fit into the motor holes on the frame. We want to generate this separatly so we create a new model object.
var model1 = new SCAD()
model1.addParameters(model)
.addParameter("heightMotor",15)
.addParameter("pinWidth",5.75)
.addParameter("cutWidth",1)
.addParameter("width",1)
var motorHolder = model1.group(
model1.cylinder()
.height("pinHeight")
.diameter("pinWidth"),
model1.difference(
model1.cylinder()
.height("heightMotor")
.diameter("motorDiameter+(width*2)"),
model1.cylinder()
.height("heightMotor")
.diameter("motorDiameter")
.translate.values(0.0,0.0,3.0)
).translate.values("0.0","0.0","pinHeight")
).toModule("motorHolder")
motorHolder.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 3 elements
In order to be able to fit the motor with the wires we cut out a section on the side of the cylinder
var cutout = model1.cube().size("cutWidth","motorDiameter","1000").center()
.translate().values("0","motorDiameter/2-1","0")
var motorHolderWithCut = model1.difference(motorHolder, cutout)
.toModule("motorHolderWithCut")
motorHolderWithCut.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 5 elements
Here is the generated OpenSCAD code for the motor mount. We need to print this 4 times...
motorHolderWithCut
$fn = 80; cutWidth = 1; heightMotor = 15; motorDiameter = 8.6; outerRingDiameter = 75; pinHeight = 10; pinWidth = 5.75; quadHeight = 3; quadWidth = 1; width = 1; module motorHolder() { { cylinder(h=pinHeight,d=pinWidth); translate([0.0,0.0,pinHeight]) difference() { cylinder(h=heightMotor,d=motorDiameter+(width*2)); translate([0.0,0.0,3.0]) cylinder(h=heightMotor,d=motorDiameter); } } } module motorHolderWithCut() { difference() { motorHolder(); translate([0,motorDiameter/2-1,0]) cube([cutWidth,motorDiameter,1000],center=true); } } motorHolderWithCut();
As our last example I will just add a Rasperry PI Zero mount to demonstrate how we can extend the frame, that we have defined in the first chapter. We load the mount into a STL file.
import java.net.URL
var model2 = new SCAD()
var urlPI = new URL("https://raw.githubusercontent.com/pschatzmann/openscad-models/master/SimpleStackablePi-Zero-Case.scad")
model2.setParameterValue("numberOfPis","1").setParameterValue("corkRadiusBack","10")
var pi = model2.scad(urlPI)
pi.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 22 elements
We include the PI into the quad defintion to combine the two designs:
quad.translate().values("widthOfPi/2","depthOfPi/2","0")
quad.importDocument(pi)
quad.display
Compiling design (CSG Products normalization)... Normalized CSG tree has 74 elements
quad
$fn = 80; heightMotor = 6; motorDiameter = 8.6; outerRingDiameter = 75; pinHeight = 10; quadHeight = 3; quadWidth = 1; module motor() { difference() { motorBase(); cylinder(h=heightMotor*3,d=motorDiameter-(quadWidth*3),center=true); } } module motorBase() { union() { motorRing(); motorInnerRing(); cube([outerRingDiameter,quadWidth,quadHeight],center=true); rotate(a=[0,0,45]) cube([outerRingDiameter,quadWidth,quadHeight],center=true); cube([quadWidth,outerRingDiameter,quadHeight],center=true); rotate(a=[0,0,45]) cube([quadWidth,outerRingDiameter,quadHeight],center=true); } } module motorInnerRing() { translate([0,0,-(quadHeight/2)]) cylinder(h=heightMotor,d=motorDiameter,center=true); } module motorRing() { difference() { cylinder(h=quadHeight,d=outerRingDiameter,center=true); cylinder(h=quadHeight*2,d=outerRingDiameter-(quadWidth*2),center=true); } } module quad() { { motorDistance = outerRingDiameter/2; translate([motorDistance,motorDistance,0]) motor(); translate([-motorDistance,-motorDistance,0]) motor(); translate([motorDistance,-motorDistance,0]) motor(); translate([-motorDistance,motorDistance,0]) motor(); } } /** A simple stackable Rasperry PI Zero case. In the parameter you can indicate the number of levels. */ numberOfPis=1; // number of PIs to be stacked widthOfPi=63.5; // x width of a rawspberry pi depthOfPi=28.7; // y depth of a rawspberry pi roundedCornersDiam=0; // minkowski on cover coverHeight=1.5; // height of cover holePos=3; // x,y position of right hole pinDiameter=2.4; // diameter of pin & hole holeDiameterOffset=0.7; // make hole bigger then pin connectorHeight=9; // height of the connector pin spacerBottomHeight=5; // height of the bottom spacer spacerTopHeight=7; // height of the top spacer partOffset=30; // we draw the parts by 3cm separated holeWidthPos=widthOfPi-holePos;// x position of left hole // the base of the top and bottom module base() { minkowski() { cube([widthOfPi,depthOfPi,coverHeight]); sphere(roundedCornersDiam,$fn=20); } } // print a single connector pin module connector(height) { cylinder(height, d=pinDiameter, $fn=100); } // print a connector pin module connectors(connectorHeight) { translate([holePos,holePos,0]) connector(connectorHeight); translate([holePos,depthOfPi-holePos,0]) connector(connectorHeight); translate([holeWidthPos,depthOfPi-holePos,0]) connector(connectorHeight); translate([holeWidthPos,holePos,0]) connector(connectorHeight); } // prints a single spacer (with a hole) module spacer(height) { difference() { size = holePos*2; cube([size, size, height]); translate([holePos,holePos,0]) cylinder(height, d=pinDiameter+holeDiameterOffset,$fn=100); } } // prints all spacers module spacers(height, offset) { size = holePos*2; translate([0,0,offset]) spacer(height); translate([0,depthOfPi-size,offset]) spacer(height); translate([holeWidthPos-holePos,depthOfPi-size,offset]) spacer(height); translate([holeWidthPos-holePos,0,offset]) spacer(height); } // bommtom of a case module piCaseBottom() { union() { base(); spacers(spacerBottomHeight,0); connectors(connectorHeight); } } // top of a pi case with an optional ornament pattern module piCaseTop() { union() { base(); spacers(spacerTopHeight,-spacerTopHeight); } } // center of a stackable pi with top and buttom spacers module piCaseCenter() { union() { piCaseBottom(); piCaseTop(); } } // print of a final case with n (parts) pi's module piStackedCase(parts=1){ piCaseBottom(); if (parts>1) { for (i = [2 : parts]) { translate([0, 0,partOffset*(i-1)]) piCaseCenter(); } } translate([0, 0, partOffset*parts]) piCaseTop(); } // print of a final single case module piCase() { piStackedCase(1); } // test print to make sure that the spacer and connector fit module testSpacerAndPin() { spacer(5,5); translate([10,0,0]) { union() { spacer(5,5); translate([holePos,holePos,0]) connector(connectorHeight); } } } // test print to check the location of the holes in the pi module testDimensions() { spacers(1,0); connectors(4); } //piCaseBottom(); // piCaseTop(); // testDimensions(); // testSpacerAndPin(); piStackedCase(numberOfPis); translate([widthOfPi/2,depthOfPi/2,0]) quad();