# CAD WITH CODE ## Introduction ### What's OpenScad ? - It's a software for creating 3D CAD Objects. It is a **script-only based modeller** that uses its **own description language**; parts can be previewed, but it cannot be interactively selected or modified by mouse in the 3D view. An OpenSCAD script specifies geometric primitives (such as spheres, boxes, cylinders, etc.) and defines how they are modified and combined (for instance by intersection, difference, envelope combination and Minkowski sums) to render a 3D model. As such, the program does constructive solid geometry (CSG). OpenSCAD is available for Windows, Linux and OS X. - It's **OpenSource** :[https://github.com/openscad/openscad/](https://github.com/openscad/openscad/) - **How to install ?** :[http://www.openscad.org/downloads.html](http://www.openscad.org/downloads.html) - **Who use it ?** : OpenScad is part of the 3D Cad Soft Free Segment which only represent 1% of the CAD users. [Source](https://www.cnccookbook.com/cnccookbook-2016-cad-survey-results-part-1-market-share/) ### OpenScad Features - Create 3D Models. - Extrusion of 2D outlines and constructive solid geometry (CSG). - Create Parametrics Designs : complete control over your design process. - CSG geometry engine. - Preview models. - Import and export files. ### CSG geometry engine Constructive solid geometry (CSG) (formerly called computational binary solid geometry) is a technique used in solid modeling. **Constructive solid geometry allows a modeler to create a complex surface or object by using Boolean operators to combine simpler objects**. Potentially **generating visually complex objects by combining a few primitive ones**. [Wikipedia](https://en.wikipedia.org/wiki/Constructive_solid_geometry) ![](https://i.imgur.com/ysMQFiM.png) ## OpenSCAD GUI ![](https://i.imgur.com/nqNP0XU.png) *[More Information about User Interface](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_User_Interface)* ### OpenScad support external editors Yes, you can use your favourite text editor to *code CAD objects*. OpenScad is able to check for changes of files and automatically recompile if a file change occurs. To use this feature enable "Design->Automatic Reload and Compile". ![](https://i.imgur.com/aDpdSE8.png) Then, hide OpenScad editor ( View -> Hide Editor) and open the file (.scad) in both softwares: OpenScand and your external editor. ![](https://i.imgur.com/bIprIZ0.png) * Support of external editors: - Atom: There is a Language [OpenSCAD package for Atom](https://atom.io/packages/language-openscad) that provides highlighting and snippets. - Emacs: OpenSCAD provides an [emacs mode for OpenSCAD](https://github.com/openscad/openscad/blob/master/contrib/scad-mode.el) files. Use the link or install via emacs package management (ELPA) with the MELPA repository. - Geany: cobra18t provides a [Geany syntax file for OpenSCAD](http://www.thingiverse.com/thing:263620). See Instructions tab in Thingiverse to install it. - Gedit: Andy Turner provides a [Gedit syntax file](https://github.com/AndrewJamesTurner/openSCAD-lang-file) for OpenSCAD. - Kate: nerd256 provides a [kate syntax file for OpenSCAD](http://www.thingiverse.com/thing:29505). See Instructions tab in Thingiverse to install it. You could create also a kate External tool to open OpenSCAD with the current file with script openscad %directory/%filename - Notepad++: TheHeadlessSourceMan provides a [Notepad++ syntax file for OpenSCAD](http://www.thingiverse.com/thing:280319). See Instructions tab in Thingiverse to install it. - Sublime: [Syntax highlighting and Customizer support](http://www.thingiverse.com/thing:67566) - Textmate: [Syntax highlighting and Customizer support](http://www.thingiverse.com/thing:67566) - VIM: vim.org provides a [VIM syntax file for OpenSCAD](http://www.vim.org/scripts/script.php?script_id=3556). - Visual Studio Code: [Free, open-source code editor](https://code.visualstudio.com/) Install the scad extension for syntax highlighting. ## References - User Manual: [https://en.wikibooks.org/wiki/OpenSCAD_User_Manual](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual) - OpenScad Language Reference: [https://en.wikibooks.org/wiki/OpenSCAD_User_Manual#The_OpenSCAD_Language_Reference](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual#The_OpenSCAD_Language_Reference) - OpenScad Cheat Sheet: [http://www.openscad.org/cheatsheet/index.html?version=2015.03](http://www.openscad.org/cheatsheet/index.html?version=2015.03) ![](https://i.imgur.com/z499m9m.png) - OpenScad Online version: [http://openscad.net/](http://openscad.net/) - Inkscape To OpenScad Converter: [https://www.thingiverse.com/thing:24808](https://www.thingiverse.com/thing:24808) ## Learning by Coding: How to design a Lego brick * Some examples come with OpenScad : File -> Examples * Important: OpenSCad units of measure are in mm -> 1unit = 1mm. If you want to work in inches create a variable. Ex: ``` Inch = 25.4 Foot = (12 * Inch) ``` ### 1. Measure your object or think about it ![](https://i.imgur.com/HJI7yTx.jpg) ### 2. Create a cube FYI : [OpenScad Language Reference](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#cube) ``` cube([3,8,9],center=false); ``` - Let's do it parametric: ``` // Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cube([brick_width, brick_length,brick_height],center=false); ``` *Note how to comment code //* *Play with the parameters* *Finish a "command" with ;* - Press F5 or ![](https://i.imgur.com/MprrP4D.png) for preview - Press F6 or ![](https://i.imgur.com/nzOK2HX.png) for render -> You can't export any model without render it. ![](https://i.imgur.com/hzYkn78.png) - Change the color: ``` // Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; color("red") cube([brick_width, brick_length,brick_height],center=false); ``` *To change the color use: color("name_of_the_color") or RGB color([1,0.5,0]) [More Info](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language)* *Note color command doesn't finis with ;* ### 3. Create the top cylinders of the brick ``` // Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cyl_diameter = 4.8; cyl_height = 1.8; number_cyl = 4; // End parameters // 3D Model color("red") cube([brick_width, brick_length,brick_height],center=false); for (a =[0:number_cyl-1]){ // Step 2 translate([3.9,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); // Step 4 translate([3.9+8,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); } ``` *Don't forget to parametrize the model* *Let's talk about [transform objects](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#Chapter_4_--_Transform)* *Let's talk about [loops](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/The_OpenSCAD_Language#For_loop)* ![](https://i.imgur.com/wKbkT6o.png) - More resolution... *[Special variables](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#.24fa.2C_.24fs_and_.24fn)* ``` // OpenScad special variables $fn = 50; //Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cyl_diameter = 4.8; cyl_height = 1.8; number_cyl = 4; // End parameters // 3D Model color("red") cube([brick_width, brick_length,brick_height],center=false); for (a =[0:number_cyl-1]){ // Step 2 translate([3.9,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); // Step 4 translate([3.9+8,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); } ``` - $fn is usually 0. When this variable has a value greater than zero, the other two variables are ignored and full circle is rendered using this number of fragments. The default value is 0. - The higher the number of fragments, the more memory and CPU consumed. - **A $fn over 100 is not recommended** ### 4. Boolean operantions: union, difference, intersection of objects * Create a complex surface or object by using Boolean operators to combine simpler objects [More Info](https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/CSG_Modelling#union) ``` // OpenScad special variables $fn = 50; //Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cyl_diameter = 4.8; cyl_height = 1.8; number_cyl = 4; // End parameters // 3D Model union(){ // Lego Piece color("red") cube([brick_width, brick_length,brick_height],center=false); for (a =[0:number_cyl-1]){ // Step 2 translate([3.9,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); // Step 4 translate([3.9+8,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); } } ``` *Play with difference boolean operators* ![](https://i.imgur.com/B9jCg4W.png)![](https://i.imgur.com/WQ1taR4.png)![](https://i.imgur.com/yNor2f3.png) ### 5. Functions and Module - You can extend the language by defining your own modules and functions. This allows grouping portions of script for easy reuse with different values. - *Functions* -> Return values - *Modules* -> Perform actions, but do not return values. - Syntax: module name_of_the_module(){...} ``` // OpenScad special variables $fn = 50; //Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cyl_diameter = 4.8; cyl_height = 1.8; number_cyl = 4; // End parameters module lego_brick(){ // 3D Model // Boolean Operator union(){ // Lego Piece color("red") cube([brick_width, brick_length,brick_height],center=false); for (a =[0:number_cyl-1]){ // Step 2 translate([3.9,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); // Step 4 translate([3.9+8,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); } } } lego_brick(); ``` * Example of use of modules: ``` use<module_example_1.scad> lego_brick(); ``` - *use* -> include modules and variables. - *include* -> includes all the code. ### 6. Internal Walls - With difference() ![](https://i.imgur.com/lssX0lm.png) ``` // OpenScad special variables $fn = 50; //Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cyl_diameter = 4.8; cyl_height = 1.8; number_cyl = 4; // Step 3 brick_wall = 1.2; // Step 4 number_cyl = 4; // Step 6 minicyl_diameter = 2.6; // Step 10 - Int cyl intcyl_diameter = 6.5; intcyl_diameter2 = 4.8; // End parameters module lego_brick(){ // 3D Model // Boolean Operator union(){ // Lego Piece color("red") difference(){ // Cube walls cube([brick_width, brick_length,brick_height],center=false); translate([brick_wall,brick_wall,-brick_wall]) cube([brick_width-brick_wall*2, brick_length-brick_wall*2,brick_height-brick_wall],center=false); } for (a =[0:number_cyl-1]){ // Step 2 translate([3.9,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); // Step 4 translate([3.9+8,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); } } } lego_brick(); ``` ### 7. Internal cylinders ![](https://i.imgur.com/nj7rVRc.png) ``` // OpenScad special variables $fn = 50; //Lego brick parameters brick_width = 15.8; brick_length = 31.8; brick_height = 9.6; cyl_diameter = 4.8; cyl_height = 1.8; number_cyl = 4; // Step 3 brick_wall = 1.2; // Step 4 number_cyl = 4; // Step 6 minicyl_diameter = 2.6; // Step 10 - Int cyl intcyl_diameter = 6.5; intcyl_diameter2 = 4.8; // End parameters module lego_brick(){ // 3D Model // Boolean Operator union(){ // Lego Piece color("red") difference(){ // Cube walls cube([brick_width, brick_length,brick_height],center=false); translate([brick_wall,brick_wall,-brick_wall]) cube([brick_width-brick_wall*2, brick_length-brick_wall*2,brick_height-brick_wall],center=false); } // Top Cyl for (a =[0:number_cyl-1]){ // Step 2 translate([3.9,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); // Step 4 translate([3.9+8,(3.9+(8*a)),brick_height]) cylinder( h = cyl_height, d=cyl_diameter, center = true); } // Internal Cyl color("yellow") for (a =[0:number_cyl-2]){ translate([brick_width/2,8+8*a,-0.2]) difference(){ cylinder( h = brick_height, d=intcyl_diameter, center = false); translate([0,0,-brick_wall]) cylinder( h = brick_height-brick_wall, d=intcyl_diameter2, center = false); } } } } lego_brick(); ``` ### 8. Export 3D Model - Save the file - Render it -> F6 - Export to .stl ![](https://i.imgur.com/gzCx0aT.png) ![](https://i.imgur.com/j7CIsUL.png) ## OpenScad Tips and Tricks **1. Example of use parametric with Lego or re-use scripts**: [LEGO.scad](https://github.com/cfinke/LEGO.scad/blob/master/LEGO.scad) ![](https://i.imgur.com/5bYq9Yc.png) **2. Modifier characters** ![](https://i.imgur.com/z2gwDlh.png) **3. Export to .dxf . From 3D to 2D -> Projection** Use projection() before define the 3D model. ![](https://i.imgur.com/huh2MWM.png) ![](https://i.imgur.com/Bh08icr.png) Press F6 ![](https://i.imgur.com/IiAGpWf.png) File -> Export -> Export to .dxf ![](https://i.imgur.com/ZAebYj8.png) **4. Living Hinges for laser cut in Openscad** ![](https://i.imgur.com/m9QOe6O.png) - [How it works ? A mathematical approach](https://www.defproc.co.uk/blog/2011/laser-cut-lattice-living-hinges/) - Code by Ari M Diacou ``` //////////////////////////// Parameters ///////////////////////////////////// //The y dimension of the hinge, parallel to the laser cuts length=30; //The x dimension of the hinge, transverse to laser cuts width=200; //The distance between parallel laser cuts d=2; //The distance between 2 collinear laser cuts hinge_length=1; //The number of hinges across the length of the hinge hinges_across_length=1; //How thick do you want the hinge to be height=5; ///////////////////////////////// Main() ////////////////////////////////////// //preview[view:north, tilt:top] projection(cut=false) linear_extrude(height) hinge(length=length,width=width,d=d,minimum_thinness=.01,hinge_length=hinge_length,hinges_across_length=hinges_across_length); ////Uncomment lines to see samples (all flat for DXF exporting) //hinge(); //hinge(d=6); //hinge(length=20, width=39,d=6,hinge_length=2.5,hinges_across_length=2,minimum_thinness=3); //hinge(length=30, width=20,d=2,hinge_length=2.5,hinges_across_length=2,minimum_thinness=3,center=true); //hinge(length=20, width=40,d=3,hinge_length=4,hinges_across_length=0,minimum_thinness=1); //linear_extrude(height=5) hinge(length=20, width=40,d=6,hinge_length=2.5,hinges_across_length=2,minimum_thinness=3); //add_hinge(width=20,length=length,center=true) square([3*length,length-1],center=true); //add_hinge(width=20,length=90) translate([5,0]) circle(d=90); //add_hinge(width=30,length=90,hinges_across_length=3) circle(d=90); //add_hinge(width=30,length=90,hinges_across_length=3,center=false) circle(d=90); //add_hinge(width=30,length=90,hinges_across_length=3,minimum_thinness=.1) circle(d=90); /////////////////////////////// Functions ///////////////////////////////////// module hinge(length=30,width=20,d=3,minimum_thinness=3,hinge_length=3,hinges_across_length=2,center=false){ //length = the y dimension of the hinge, parallel to the laser cuts //width = the x dimension of the hinge, transverse to laser cuts //d=the distance between parallel laser cuts //What is the minimum distance that two parallel lines can be apart before the laser does something catastrophic? E.g. setting uncontrollable fire to the work piece. This is "minimum_thinness" //hinge_length=the distance between 2 colinear laser cuts //hinges_across_length=the number of hinges across the length of the hinge //center is a boolean value, if true, place the center of the rectangle at the origin, if false, put the bottom left corner at the origin (just like square() and cube()) ep=.00101;//epsilon, a small number,=1.01 micron, a hack (for OpenSCAD 2015.03) used to make square()'s which look like lines (which OpenSCAD doesn't support). Hopefully, your laser has a function which says something like "ignore cuts less than THRESHOLD apart", set that to anything greater than ep. adjust=center?-[width,length]/2:[0,0];//a vector for adjusting the center position th=d/2<minimum_thinness?ep:d/2;//If the distance between lines is less than the minimum thickness, just make linear cuts, specifically, set the width=th=thickness of the squares to ep, which is just above 1 micron (for 1=1mm slicers) n=floor(width/d); m=floor(abs(hinges_across_length)); echo(str("Number of hinges (m)=",m)); //input cleaning, ensures m ϵ {non-negative integers} echo(str("Suggested filename: Living Hinge-",length,"x",width,"mm-h=",m,"x",hinge_length,"-th=",th)); echo(str("The distance between parallel laser cuts (d) is: ",d," mm.")); //the length of the short lines short=(length-m*hinge_length)/(m+1); //the length of the long lines long=(length-(m+1)*hinge_length)/(m); echo(str("There should be n=",n," links in the hinge.")); translate(adjust) difference(){ square([width,length],center=false); if(m==0) //In the special case where |hinges_across_length|<1, the hinge should look like: // | --------------------------------------| // |-------------------------------------- | // | --------------------------------------| // |-------------------------------------- | for(i=[0:n]) translate([i*d,(pow(-1,i))*hinge_length]) // (-1)^i,{iϵZ} = {-1,+1,-1,+1,...} square([th,length]); else //A hinge with hinges_across_length=2 should look like: // |------------ ------------ ------------| // | ----------------- ----------------- | // |------------ ------------ ------------| // | ----------------- ----------------- | for(i=[0:n]){ //Iterating across x translate([i*d*1,0]){ //Do the x translation seperate from the y translations if(i%2==1) //For odd columns for(j=[0:m-1]){ translate([0,hinge_length+j*(long+hinge_length)]) square([th,long]); } if(i%2==0) //For even columns for(j=[0:m]){ translate([0,j*(short+hinge_length)]) square([th,short]); } } } } } module add_hinge(length=30,width=20,d=3,minimum_thinness=3,hinge_length=3,hinges_across_length=2,center=true){ //add_hinge() modifies another 2D object, by adding a hinge which is centered on the origin (by default, this can be changed to false, so that the bottom left corner of the hinge is at the origin. It uses the same parameters as hinge(). //First, difference() a rectangle the size of the hinge from the child object (makes a hole for the hinge //Second, union() a hinge with First (puts the hinge in the hole) //Third, intersection() the child object with Second (cuts off any extra hinge that sticks out past the child object) intersection(){ children(); union(){ hinge(length=length,width=width,d=d,minimum_thinness=minimum_thinness,hinge_length=hinge_length,hinges_across_length=hinges_across_length,center=center); difference(){ children(); square([width,length],center=center); } } } } ``` ## Visual Programming: BlocksCAD BlocksCAD is a cloud-based 3D modeling tool that encourages users to learn math, computational thinking and coding concepts through visualization and designing models to be 3D printed. - Block programming - Online - Export .stl - Export code to OpenScad ![](https://i.imgur.com/yzlJ8FZ.png) ![](https://i.imgur.com/H1q2xoT.png) ## OpenScad Libraries ### <lasercut.scad> Module for openscad, allowing 3d models to be created from 2d lasercut parts, with a flat file automatically generated. Updated, not just lasercut can now pass the parameter milling_bit for CNC machines, for the bit to cut in to the corners https://github.com/bmsleight/lasercut ## From Inkscape to OpenScad (2D - 3D) * Install Inkscape Extension: * Inkscape To OpenScad Converter: [https://www.thingiverse.com/thing:24808](https://www.thingiverse.com/thing:24808) * Example Simple Design: ![](https://i.imgur.com/ojsDPBz.png) - Select object -> Path -> Object to Path ![](https://i.imgur.com/dC09TlR.png) ![](https://i.imgur.com/KKwQ8RB.png) ![](https://i.imgur.com/mnKOSUW.png) - Path -> Difference ![](https://i.imgur.com/s7981JQ.png) ![](https://i.imgur.com/7m7dKJr.png) * Example with GearGenerator Inkscape: - Extensions -> Render -> Gear Generator -> Gear ![](https://i.imgur.com/yK9EPVn.png) ![](https://i.imgur.com/VJ0AnEx.png) ![](https://i.imgur.com/U3soTvj.png) ![](https://i.imgur.com/RXjHKM3.png) ## Python to generate .scad : a speech recognition example - You should have installed python, and the speechrecognition library. ``` import pyaudio import speech_recognition as sr #for index, name in enumerate(sr.Microphone.list_microphone_names()): # print("Microphone with name \"{1}\" found for `Microphone(device_index={0})`".format(index, name)) def text2int(textnum, numwords={}): if not numwords: units = [ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", ] tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"] scales = ["hundred", "thousand", "million", "billion", "trillion"] numwords["and"] = (1, 0) for idx, word in enumerate(units): numwords[word] = (1, idx) for idx, word in enumerate(tens): numwords[word] = (1, idx * 10) for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0) current = result = 0 for word in textnum.split(): if word not in numwords: raise Exception("Illegal word: " + word) scale, increment = numwords[word] current = current * scale + increment if scale > 100: result += current current = 0 return result + current r = sr.Recognizer() r.pause_threshold = 1.0 r.phrase_threshold = 1.0 r.non_speaking_duration = 1.0 f= open("speech_to_cad.scad","w+") with sr.Microphone() as source: print("STAR TO DESIGN...") r.adjust_for_ambient_noise(source) audio = r.listen(source) print("TIME OVER, THANKS") try: primitiva = r.recognize_google(audio).lower() data = primitiva.split() for temp in data: print temp #primitiva = primitiva.split(' ':,1) print(data[0]+"(\""+data[1]+"\")"+data[2]+"(h="+data[3]+"$fn=100);"); #color("blue") cylinder(h=10,$fn=100); #print(text2int(primitiva, numwords=1)) f.write(data[0]+"(\""+data[1]+"\")"+data[2]+"(h="+data[3]+",$fn=100);") f.close() except: pass; ``` 1. Open .scad in OpenScad -> File should be defined in python code ( speech_to_cad.scad ) 2. Run python code 3. Speak ( color green shape height) 4. Be patient...is not perfect...yet :-) ![](https://i.imgur.com/3BeeFtT.png) ![](https://i.imgur.com/Yg4500V.png) ![](https://i.imgur.com/FNA4AdV.png)