OpenSCAD tips for creating reusable modules

OpenSCAD is a really powerful tool for creating 3D objects. Unlike other tools such as FreeCAD, the parts are created programmatically, so you have to write code to create your parts. That gives you the ability to create independent modules that can be organized in separate files and imported by other designs. This article will give you tips for creating reusable modules and provide examples.

The source code of all examples in this article can be found in openscad_tips_examples.zip.

Ok, let’s start!

Tip 1. Parametrize your modules

The reason what I like the most OpenSCAD over other design tools is because of its programmatic nature for creating objects. You can create modules that can be parametrized to create dynamic objects.

Here is an example of a battery case module:

module batt_case_AA(t=0,thickness=2, nx=2, ny=1, radius=-1, extra_size = 0)

This module accepts a few parameters that let us customize the appearance of the case by only changing their default values. So we can create a case for more than one battery, with a customized thickness, radius of the borders, etc.

Using default parameters makes the interface cleaner without losing flexibility because we only need to set those values that we want to change:

batt_case_AA(nx=2); // a battery case with two batteries

openscad_param_example

 

Tip 2. Export relevant dimensions using functions

OpenSCAD defines two commands for importing an external module into your design: ‘include’ and ‘use’ commands. As the documentation says, the first one acts as if the contents of the included file were written in the including file, and the second one imports modules and functions, but does not execute any commands other than those definitions.

I find the ‘use’ command particularly useful for creating reusable designs because it hides all global variables and any other command defined in the included file. You can export the dimensions you need by using functions.

For example, in the previous example we saw how to create a parametrized battery case. The case size will depend on the parameter values. This is the code of the function which returns the size vector of our parametrized case:

function get_batt_case_size
  (batt_diam, batt_len, thickness=2, nx=2, ny=1, radius=-1, t=0) =
      [(batt_diam+t)*nx + (nx-1)*SEPARATOR_THICKNESS + 2*thickness,
      (batt_len+t)*ny + 2*(1.5 + cable_diam + batt_terminal_thickness) + 2*thickness,
      (batt_diam+t) + 2*thickness];

Now we can get the battery case size in our new designs. The following code shows how to use that function to adds screw tabs to our battery case:

use <parts/battery_case.scad>

// ...

case_size = get_batt_case_size_AA(nx=num_batts, radius=thickness, thickness=thickness);

batt_case_AA(nx=num_batts, radius=thickness, thickness=thickness);

translate([case_size[0]/2 - thickness,0,-case_size[2]/2])
screw_tab(x=5 + thickness,y=10, z=thickness,d=4);

rotate([0,0,180])
translate([case_size[0]/2 - thickness,0,-case_size[2]/2])
screw_tab(x=5 + thickness,y=10, z=thickness,d=4);

 

battery_case_screw_example

 

Tip 3. Add the “tolerance” parameter

3D printed parts are not perfect and they may have a little error over the original design. Creating a tolerance parameter may be a good idea to compensate that error easily, especially in those situations where we have to fit together two different parts.

You can find an example of that in the GoPro module. If we add a value to the ‘t’ parameter we will get an extra space between matching parts.

openscad_tolerance_example

 

Tip 4. Select good reference points

The reference point should be that which lets you place the part in the easiest way. If you have to do a lot of maths in order to place your part in other designs you may have chosen a bad reference point.

You may need additional reference points to assembly different parts in a new design. We are going to illustrate that using the ‘gopro_rounded_mount’ module included in gopro.scad file:

// len = height of the mount (size_y)
// alpha = angle of the mount pole
module gopro_rounded_mount(len=15, alpha=30,t=0.4, extra=0)

The reference point is placed in the bottom-center position which is good for placing in any design. However, that module accepts a value for the height of the mount and another for the angle which makes it really difficult to find the exact position of the screw axis. To solve that, a function was included to get that additional reference point:

function get_rounded_mount_axis_ref(len=15, alpha=30, t=0.4, extra=0) =
  [0,
  (((max(wall_width,len) - (wall_width/2) * (sin(alpha) + 1 ) ) / sin(alpha)) + wall_width/2) * (1 - cos(alpha)),
  (((max(wall_width,len) - (wall_width/2) * (sin(alpha) + 1 ) ) / sin(alpha)) + wall_width/2)*sin(alpha)];

And let’s see how to use it:

use <gopro.scad>

gopro_rounded_mount(len=20,alpha=35);

translate(get_rounded_mount_axis_ref(len=20,alpha=35))
  rotate([0,90,0])
    cylinder(r=2,h=40,center=true, $fn=20);

openscad_gopro_axis_ref_example

 

Tip 5. Provide “removal” parts

Sometimes, we want to create objects which may be attached or embedded inside other ones. In those cases, creating the module is not enough to be used and we need to create additional modules to help use them. Let’s see an example:

We have created a module to attach a gimbal motor and we want to join it to another part, let’s say, a gopro case. The problem here is that we need to modify the gopro_case to add the holes for the motor screws and we don’t know their details such as the diameter, separation, etc.

The solution is to provide a “removal” part module in addition to the motor module, so we can use it without knowning the dimensions of the motor screws and separation.

In this example, the removal module is named “motor_front_drills”, and it contains a parameter to define the size of the hole which has to be greater than the case width.

module gopro_case_with_motor()
{
  difference()
  {
    gopro_case();
 
    translate([get_gopro_case_size()[0]/2,0,0])
    rotate([0,90,0])
    motor_front_drills(screw_hole = 10);
  }
 
  translate([0,-get_gopro_case_size()[1]/2,0])
  rotate([90,0,0])
  gopro_support_mount(len=15);

  translate([get_gopro_case_size()[0]/2,0,0])
  rotate([0,90,0])
  motor_front_mount();
}

This is the final result:

removals_example2

 

Leave a Reply

Your email address will not be published. Required fields are marked *