This post describes an approach to create large assemblies in the parametric CAD software OpenSCAD.
Background – About OpenSCAD
OpenSCAD differs greatly from typical CAD programs, in that it uses a descriptive programming language to create 2D and 3D geometry. Rather than creating geometry using a set of tools in an interactive interface, geometry is described programmatically, and rendered for display in the compiler viewport or export.
OpenSCAD is a functional language, in that assigned variables are immutable (they cannot be reassigned), which contrasts those available in most common languages – C, Python, etc. If I am being honest I don’t understand the intent behind this, but regardless it does present challenges in how problems must be approached.
The great advantage of OpenSCAD is the flexibility and control that it wields compared to typical CAD packages – think LaTex vs Microsoft Word. The programmatic nature of OpenSCAD lends itself very well to making highly parametric parts and assemblies, and the ability to create subroutines allows for geometry to be reused however the programmer sees fit.
Background
The original goal for this project was for the modelling of my PrintNC-Derivative CNC Router, which I initially intended to model in OpenSCAD for its high degree of control when creating highly parametric designs*.
This necessitated a way to effectively reuse code to create the large assembly in an efficient manner.
Ultimately however, due to the poor performance (OpenSCAD only runs on a single CPU core), time consuming modelling process, and incompatibility with other programs (STL export only), I bit the bullet and switched to Autodesk Inventor.
*Really this is something in which OpenSCAD is not fit-for-purpose, but there is a certain elegance to building a complex assembly line-by-line, with the entire model stored in a handful of plain .txt files.


Class Definition
For each physical class of parts, for example linear rails or ballscrews, a ‘pseudo-class’ is defined within a new file, complete with a set of attributes, and methods to create geometry. For the linear rail file ,three sets of attributes, for HGR15, 20, and 25mm size rails are first created. Each set of attributes is contained within a nested list, with a string identifier for each (OpenSCAD does not support dictionaries).
The nested lists are contained within functions, which can be accessed to extract attributes. These are functions in the OpenSCAD sense, which can only hold, manipulate, and return data, but cannot perform actions to create or modify geometry. Typically they are used to contain mathematical functions, for example to create a sine wave or parabola.



The rail Class is now defined, using ‘module’. In OpenSCAD a module is a sub-block of code, which can take in values and create geometry, but cannot return anything.
To call a new instance of the LinearRail() module (effectively it is like creating a new Class instance), the user specifies which set of attributes they wish to use, here HGR20_Att() for a HGR20 20mm size of rail, which Method (a submodule within LinearRail()), here “GENERATE RAIL WITH CARRIAGE”, and the necessary parameters – rail length, number of carriages, etc. If parameters are not specified, they will be assigned defaults.
The required attributes are then read out of the attribute function into local constants, using the separate ReturnAtt() function, which searches the attribute list for the specified identifier, and returns the corresponding value if found.
For linear rails there exists multiple options of carriage, namely CA and HA variants, which have different lengths and hole patterns. Attributes for each variant are stored and read out into the Class scope, but only a single value can be used by the Methods. To handle this a small piece of logic singles out the appropriate values depending on which carriage type the user inputted as a parameter.



With local attributes now defined, the user requested Method can now be run, using a simple if/else chain to call each submodule. For linear rails there exist several different Methods. These are:
- GenerateRailWithCarriage() – generates a linear rail with a single carriage. This submodule makes use of both the GenerateRail() and GenerateCarriage() submodules, by calling LinearRail(“GENERATE RAIL”), and LinearRail(“GENERATE CARRIAGE”).
- GenerateCarriage() generates a linear carriage, making use of the RAILPROFILE() submodule by calling LinearRail(request=”RAIL PROFILE”, attributes=attributes), and also the CarriageHolePattern() submodule, which can be called directly without needing to create a new class instance.
- GenerateRail() generates a linear rail of the requested length, calling the RailHolePattern(), and RailProfile() submodules directly.
- RailHolePattern() generates the linear pattern of mounting holes in the rail. This submodule, like CarriageHolePattern(), is important in that it demonstrates a very useful tool in OpenSCAD, the children() command. Rather than creating geometry directly, the use of children() means that the pattern can be instead inherited by external geometry, for example to position the mounting holes within GenerateRail(). Because the method can be called from outside the Class, it can be used for example, to specify the mounting hole pattern for the rail, on a completely separate part such as a frame member.
- RailProfile() generates the cross-section profile of the rail.




Other Classes
Ballscrew() by default can be used to generate SFU1204 and SFU1605 size ballscrews, with a number of Class Methods to generate various configurations, hole patterns, and as well as standard bearing blocks.



RHS() can generate standard square and rectangular hollow sections. By default there are attribute sets for 50x50x6mm, 75x75x6mm, and 75x50x4mm sections.


Files
https://github.com/marinmersenne2357/OpenSCAD-Pseudo-Class-for-Large-AssembliesModelling