openscad

OpenSCAD tutorial

intro

OpenSCAD is advertised as The Programmers Solid 3D CAD Modeller. First released in 2001, it has a very active developing community on github and is used a lot for parametric design of parts and components, for example on thingiverse. Some of the strong points of OpenSCAD:

  • relatively small package (21MB)
  • file storage in plain text
  • parametric design by default
  • open source, multiplatform
  • export directly to printable STL
  • import of STL, vector drawings

downside:

  • no easy ‘mating’ of assemblies
  • no easy tooling for chamfered edges and complex shapes.

The first one of these downsides is one of the most powerful strong points in SolidWorks (and other CAD packages). In the following example (eye mechanism) all the parts are separate modules, for an assembly they have to be positioned by manually assigning the correct position. For single parts, parametric components (think gears, pulleys, LEGO bricks) it works very well.

Assembly of parts for an eye mechanism in OpenSCAD

Assembly of parts for an eye mechanism in OpenSCAD

Getting Started

A bottom-up level to get started is just following the manual (tutorial) - or better, the cheatsheet which I still use at every occasion. A top-down approach would be to go to thingiverse (or OpenSCAD website), download an example, try out and reverse-engineer.

For this tutorial the simplest useful shape I can think of: a rectangular box:

difference(){ //substract second shape from first shape
        cube([50,60,20]);
        translate([2,2,2])cube([46,56,20]);
    }
simple box drawing, no functions, no frills

simple box drawing, no functions, no frills

I start often like this: shapes with hard-coded values. Also very often the modifier you start with is a difference() of two shapes. After the ‘preview’ you need to render the drawing (takes a bit longer) in order to be able to save it as *.stl file.

Rendered box. visually not much different (but major difference with large or complex drawings)

Rendered box. visually not much different (but major difference with large or complex drawings)

Now, the function drawing the box (like c code) can take parameters. You can declare them ‘global’ at the top of the code, or pass them in the function:

width = 60;
depth = 50;
height = 20;

difference(){ //substract second shape from first shape
        cube([width,depth,height]);
        translate([2,2,2])cube([width-4,depth-4,height]);
    }

Passing everything as parameters (variables) in the function would give the following, (setting also the wall thickness, a very useful parameter for things you’ll print. Also, it might be better to set the INSIDE size rather than outside size of a box)

box(50,60,20,2); // make a box with width, depth, height, wall thickness

module box(width, depth, height, wall){
    difference(){ //substract second shape from first shape
        cube([width+2*wall,depth+2*wall,height+wall]);
        translate([wall,wall,wall])cube([width,depth,height+2*wall]);
    }
}

The next very useful command is a hull. This will create an envelope of a set of shapes, and is the next best thing OpenSCAD can do towards rounded edges or organic shapes. The following box function uses a hull around 4 cylinders instead of a box:

module box(width, depth, height, wall){
    difference(){ //substract second shape from first shape
    hull(){
        translate([0,0,0])cylinder(h=height,r=wall);
        translate([width,0,0])cylinder(h=height,r=wall);
        translate([width,depth,0])cylinder(h=height,r=wall);
        translate([0,depth,0])cylinder(h=height,r=wall);
        
    }
        translate([0,0,wall])cube([width,depth,height+2*wall]);
    }
}

When using cylinders and spheres in OpenSCAD it makes sense to set the rendering resolution (or number of segments in a circular shape), in order to reduce rendering time. You can do this by setting the $fn = 40; function at the top of the code.

box as hull around 4 cylinders

box as hull around 4 cylinders

Workflows

The VScode plugin

The VScode plugin for OpenSCAD offers syntax highlighting and function completion (and all the other nice features). It also adds three buttons to the top-bar for rendering your design (for which a separate OpenSCAD window will be opened).

The plugin:

Plugin for VSCode

Plugin for VSCode

Saving the *.scad code in VSCode will sync it with the OpenSCAD instance (which you have to have running in the background):

VScode with OpenSCAD syntax highlighting (and small buttons for preview, render and export)

VScode with OpenSCAD syntax highlighting (and small buttons for preview, render and export)

The separate renderwindow will open when one of the buttons for preview or render is pressed:

Render window (just an instance of OpenSCAD without the editor)

Render window (just an instance of OpenSCAD without the editor)

importing STL

A very useful function for (for example) making a well fitting enclosure for your electronic design is the option to import an *.stl file. In the following example a board design (rendered using KiCAD, the STEP file converted using FreeCAD to an *stl file). With the instruction:

color("white")translate([-24.5,77,4])import("board.stl",convexity = 10);

an STL file is imported, placed at the right spot (convexity is necessary to set for complex shape rendering). In this case color("white") will render the entire STL white.

a box drawn around an imported *.stl file of a PCB

a box drawn around an imported *.stl file of a PCB

3D shape to 2D

The magic command here is projection. The following example takes a simple 3D shape of an elliptic lamp shade:

module lampshade() difference(){
    scale([1,1,0.5])sphere(150);
    scale([1,1,0.55])sphere(130);
    translate([0,0,-75])cylinder(d=40,h=200);
    //translate([-200,-200,-200])cube([400,200,400]);
}
simple lampshade of a stretched sphere (with 40mm mounting hole for fitting)

simple lampshade of a stretched sphere (with 40mm mounting hole for fitting)

This function is put into a projection ’loop’ which will shift the shape ’through’ the x-y plane and draws its outline (projected shape). This drawing could be exported as *.svg file and cut on a laser (more programming would be neede to make automatic laset-bed-size design files):

module slice(){
    for(i=[-75:8:75])
    translate([i*40,0,0])
         rotate([0,0,i*15])
            projection(cut=true)
                    translate([0,0,-i])
                        lampshade();
}
unorganised series of slices as result of the imported shape

unorganised series of slices as result of the imported shape

Similar to the ’lampshade’ shape, also an *.stl file of any object could be sliced and made into a cuttable drawing. The drawing (without the 3D shape) can indeed be exported as *.svg for cutting:

Save option of *.svg)

Save option of *.svg)

2D to 3D

A common workflow in Fusion360 and other packages is to make a 2D drawing as basis, which is subsequently extruded and processed further. Complex shapes, such as aluminum extrusion profile would take quite long to model using cylinders and boxes. A different workflow is the following:

For an aluminum extrusion profile, I take a (fairly random, sharp looking) drawing from an image search, in this case a *.jpg file:

extrusion profile - profile image

extrusion profile - profile image

I open this file in inkscape:

Using the bitmap tracing function

Using the bitmap tracing function

trace the bitmap in inkscape path menu -> trace bitmap,

profile with adjusted fill and line-width settings

profile with adjusted fill and line-width settings

scale and adjust color (so it is now a line drawing) and save as *.svg file.

With the following line the file can now be used as extrusion template:

linear_extrude(height = 100, center = true, convexity = 10)
		import(file = "profile.svg");
extrusion profile based on imported image

extrusion profile based on imported image

Note: in some situations (i.e. older versions of inkscape/OpenSCAD) sizes used in the *.svg might not correspond to the sizes used in OpenSCAD. This might be a whole metric-imperial-pixel-locale settings thing.

Also, when using a file to extrude or save, it is best to save the *.scad file in the same directory (or save it somewhere you can easily use relative paths)

Other resources

  • openjscad: online parametric modelling

  • tinkercad offers similar programming style (but more ‘scratch’ like)

  • you can ask chatGTP for openSCAD scripts:

    could you provide me an scad script for an enclosure for an Arduino board

results in the following script (which is really simple, but might do the trick):

// Arduino Enclosure

// Dimensions of the Arduino Uno board
arduino_width = 68.6;
arduino_length = 53.4;
arduino_height = 11.8;

// Add some clearance for the board
clearance = 2;

// Dimensions of the enclosure
enclosure_width = arduino_width + 2 * clearance;
enclosure_length = arduino_length + 2 * clearance;
enclosure_height = arduino_height + clearance;

// Create the enclosure
difference() {
    // Outer shell
    cube([enclosure_width, enclosure_length, enclosure_height]);

    // Subtract the space for Arduino board
    translate([clearance, clearance, 0])
        cube([arduino_width, arduino_length, arduino_height]);
}