The programmer's CAD: OpenSCAD
OpenSCAD is a GPLv2-licensed 3D computer-aided design (CAD) program
best described as a "programmer's CAD"; it is available for
Linux, Windows, several flavors of BSD, and macOS. Unlike the majority of 3D-modeling software packages which are
point-and-click, the OpenSCAD website describes the project as
"something like a 3D compiler
", where models are generated using
a scripting language. It is a unique way of approaching CAD and has many
real-world applications that may be of interest.
Like the FreeCAD project we have previously looked at, OpenSCAD can be used to build 3D-models suitable for everything from 3D-printing to CNC machining. Unlike FreeCAD, however, the solitary way to create models is by programming them using the OpenSCAD scripting language. Once programmed, models produced by OpenSCAD can be exported in a variety of formats, including notably STL, SVG, and PNG.
The Qt-based interface provided by OpenSCAD is fairly simple; on one side a code editor is provided to write scripts, while the other provides a view of the generated model and a console for messages. Making a model starts with coding modules that generate primitives like cylinders and cubes, then those primitives are manipulated and combined in code to build more complicated objects. Notably, OpenSCAD is a unit-less CAD program; it leaves the units to be decided once the model is exported. This article will focus on the process of creating one of the three components for the following model:
The image above shows OpenSCAD rendering a model for a 3D-printable blast gate, which is a device that connects inline to a pipe for a vacuum system to help focus vacuum pressure where it is needed. It is a reproduction I created from scratch of this design by the user Jimbobareno on Thingiverse. It consists of three parts: the flanges (grey), the spacer between them (orange), and the movable gate (green). The model is viable for several different pipe sizes with only minor modifications, but those modifications are more complicated than merely scaling the model; doing so would change not only the pipe size, but also the holes for the bolts that ultimately hold the parts together. To make this model adaptable, it needs to be able to scale certain aspects while leaving others alone; this makes it a great candidate for OpenSCAD. In fact, the entire model can be built using an OpenSCAD script based on three variables (outer pipe diameter, screw hole size, and wall thickness) to produce a 3D-printable model of any size blast gate.
Writing OpenSCAD code is often done using the editor provided in the interface, but those who want to use an external editor can do so. As an example of how to program a model using OpenSCAD, we will focus on the flange of the the blast gate. Here is the code to generate one:
module flange(pipeDiameter, pipeWallsize, fastenerSize) {
$_outerPipeRadius = ((pipeDiameter / 2) + pipeWallsize);
$_flangeSize = ($_outerPipeRadius + 20) * 2;
difference() {
union() {
cube([$_flangeSize, $_flangeSize, 4], center = true);
translate([0,0,2 - 0.001])
cylinder(r=$_outerPipeRadius, h=26);
}
translate([0,0,-4])
cylinder(r = $pipeDiameter / 2, h=32);
translate([-($_flangeSize / 2) + 8, -($_flangeSize / 2) + 8, -3])
cylinder(r = (fastenerSize / 2), h=6);
translate([($_flangeSize / 2) - 8, ($_flangeSize / 2) - 8, -3])
cylinder(r = (fastenerSize / 2), h=6);
translate([($_flangeSize / 2) - 8, -($_flangeSize / 2) + 8, -3])
cylinder(r = (fastenerSize / 2), h=6);
translate([-($_flangeSize / 2) + 8, ($_flangeSize / 2) - 8, -3])
cylinder(r = (fastenerSize / 2), h=6);
}
}
The flange module accepts three parameters: pipeDiameter, which is the outer diameter of the pipe to be inserted, pipeWallsize, which is the wall thickness of the pipe fitting, and fastenerSize which is the diameter of the hole for the bolt. When reading OpenSCAD code, it is easiest to read the program "inside out." Consider this segment of the script from above:
union() {
cube([$_flangeSize, $_flangeSize, 4], center = true);
translate([0,0,2 - 0.001])
cylinder(r=$_outerPipeRadius, h=26);
}
This snippet defines a cube (rectangular solid) by calling the cube function with a width and height defined by the $_flangeSize variable calculated at the start of the module, and a fixed depth of four. The last parameter, center, indicates that the cube should render centered at the origin of the workspace. Following the cube function, we have a translate statement and its target, the cylinder statement; these operations can be considered a single action of creating a cylinder with a radius of $_outerPipeRadius and a height of 26, then moving that cylinder to the x,y,z coordinates of (0, 0, 1.999) in the workspace. $_outerPipeRadius is the radius of the desired pipe (pipeDiameter), plus the thickness of the wall specified by pipeWallsize. These statements place the cylinder centered on top of the cube (and 0.001 units "inside" of it). Shown below is a rendering of the model for a pipeDiameter of 61:
At this point in the process, the cylinder and cube are independent, overlapping solids to OpenSCAD. To join them together, we wrap the code with a union operation, which takes all of the solids defined within it and combines them into a single solid in the model. The union operation is why the cylinder was placed 0.001 units "inside" of the cube: without an overlap, OpenSCAD's union operation won't join them.
The process of creating primitive solids programmatically, placing them with other solids, and then joining them together into a new solid can also happen in reverse. Looking at the full code for the flange module, readers will note the difference operation, which works in an opposite fashion to union by subtracting one solid from another. In example, the difference operation contains the following immediately after the union:
translate([0,0,-4])
cylinder(r = $pipeDiameter / 2, h=32);
This operation creates a second cylinder at the origin that is the exact size of the desired pipe, which will always be smaller in diameter than the one generated in the union (by pipeWallsize units). This new cylinder's height is arbitrary; what is essential is that it be taller than the model's height. Combining the union and the new cylinder within the difference operation causes the new cylinder to be subtracted from the union, creating a hole. An animated example of this process for a pipeWallsize of 1.5 units may help visualize the operation.
The same difference process is then repeated for each of the bolt holes created on the flange: create a cylinder of correct diameter and sufficient height, position it where the hole should be, and then the difference operation subtracts it from the solid created by the union code block.
The full script for the blast gate example used in this article is available to readers under an MIT license. It includes the code used to construct the flange shown here, the spacer, and the gate. It additionally provides examples of scripting language features not covered in this article.
One of the most interesting abilities of OpenSCAD is a feature called the Customizer, which parses an OpenSCAD script and generates a "customization panel" that allows others to customize the model without having to do any programming. OpenSCAD provides a special syntax for variables placed at the top of a script, which is then translated into various form elements used by the Customizer. For the blast gate model, our customizable values consist of four variables at the top of the script:
// The outer diameter of the pipe being used.
$pipeDiameter = 61;
// The wall thickness of the pipe portion of the flange
$pipeWallsize = 1.5; // [1.5:0.1:10]
// The diameter of the fastener holes
$fastenerSize = 3.7; // [1:0.1:14]
// The part of the blast gate to render
$render = "all"; // [all, flange, spacer, gate]
By using the Customizer tool's comment-based syntax, our model can be quickly (and correctly) customized via the user interface. Above, the comments directly before each variable provide a description, and the inline ones define the acceptable values (i.e. any value between 1.5 to 10 with a step of 0.1 for $pipeWallsize). For variables that do not provide an indication one way or another, a generic form element is created from the data type of the variable. Here is the interface the Customizer tool generates based on this metadata:
Note that while OpenSCAD provides a graphical user interface, it can also be used from the command line for several tasks. For example, the Customizer can be used in an automated fashion from the command line to export a model based on a text file containing the customization values.
There are many different OpenSCAD libraries of open-source parametric objects available online. The OpenSCAD MCAD Library is one example of a community-contributed collection of SCAD scripts to generate various useful components like gears, nuts, bolts, and other standard constructions. Cloning this repository into the OpenSCAD library directory makes them available for import:
use <MCAD/boxes.scad>
roundedBox(size = [10, 20, 30], radius = 3, sidesonly = false);
The above uses the MCAD roundedBox module to generate a box with rounded edges:
OpenSCAD was initially released in 2010, with 19 releases since; the latest stable version was released in May 2019. There does not appear to be a steady cadence of releases by the project's 136 contributors, but a review of the OpenSCAD GitHub page hints at a new release in 2020. In addition to the MCAD library we discussed, various other user-contributed open-source libraries of models for OpenSCAD are also available.
The examples we have looked at in this article have been trivial when compared to what is possible. In addition to the simple operations, OpenSCAD supports conditionals, loops, trigonometric functions, and more. The language reference provides complete documentation of the scripting language's capabilities, and a helpful cheat sheet is also available. If additional assistance is needed, the project provides a mailing list (that is bidirectionally connected to its web-based forum) and the #openscad IRC channel on irc.freenode.net. For programmers looking for a 3D-modeling tool for their next project, OpenSCAD is worth a look.
Posted Aug 26, 2020 23:15 UTC (Wed)
by michaelkjohnson (subscriber, #41438)
[Link] (1 responses)
A minor clarification that might help those just learning OpenSCAD:
Implicit union
At this point in the process, the cylinder and cube are independent, overlapping solids to OpenSCAD. To join them together, we wrap the code with a union operation, which takes all of the solids defined within it and combines them into a single solid in the model.
That's potentially misleading, depending on how it is read. The union operator is not needed to merely fuse geometrical elements. OpenSCAD doesn't have a concept of physically-conjoint independent objects, and mere concatenation of objects is geometrically sufficient. The union operator is useful in the context of other operators that interpret their child objects depending on position, primarily difference, as in the case that you used it. It's used to organize the object tree before rendering, and doesn't add semantics to the rendering process itself. Put another way, you are grouping operations not solids.
Remark: union is implicit when not used. But it is mandatory, for example, in difference to group first child nodes into one.I've seen plenty of OpenSCAD code that overuses union and in fact especially in my first OpenSCAD code overused it a lot before I understood that point.
Posted Aug 27, 2020 18:10 UTC (Thu)
by coogle (guest, #138507)
[Link]
Posted Aug 26, 2020 23:20 UTC (Wed)
by michaelkjohnson (subscriber, #41438)
[Link] (4 responses)
Posted Aug 27, 2020 6:37 UTC (Thu)
by smurf (subscriber, #17840)
[Link]
Posted Aug 27, 2020 18:05 UTC (Thu)
by coogle (guest, #138507)
[Link] (2 responses)
Posted Sep 3, 2020 16:55 UTC (Thu)
by t-paul (guest, #141164)
[Link] (1 responses)
Posted Sep 3, 2020 19:28 UTC (Thu)
by michaelkjohnson (subscriber, #41438)
[Link]
It surprises me not at all that nophead (of NopSCADlib) provides an example taking advantage of the dynamic scope:
http://forum.openscad.org/Special-variable-scoping-rules-...
Posted Aug 26, 2020 23:27 UTC (Wed)
by michaelkjohnson (subscriber, #41438)
[Link] (2 responses)
Implicit union
In my OpenSCAD experience, $ is used for reserved variables such as $fn, and normal variables are not commonly prefixed with a $. I see that you used both a $ and a $_ convention that I don't recognize from other OpenSCAD exemplars. Is there a reason beyond personal convention for this form in your example?
Why $ in variable names?
Why $ in variable names?
Why $ in variable names?
Why $ in variable names?
Why $ in variable names?
It is reasonably common to have MCAD packaged with OpenSCAD; for example, Fedora packages both openscad and openscad-MCAD.MCAD and NopSCADlib
Posted Aug 27, 2020 16:07 UTC (Thu)
by gerdesj (subscriber, #5446)
[Link]
My printer is going to be very busy soon.
Posted Aug 27, 2020 18:13 UTC (Thu)
by coogle (guest, #138507)
[Link]
Posted Aug 27, 2020 12:08 UTC (Thu)
by esemwy (guest, #83963)
[Link]
https://solidpython.readthedocs.io/en/latest/
MCAD and NopSCADlib
MCAD and NopSCADlib
SolidPython and ViewSCAD
https://github.com/nickc92/ViewSCAD

![Blast Gate Model [Blast Gate Model]](https://static.lwn.net/images/2020/openscad-model-sm.png)