Monday, December 22, 2025

Project box designed with OpenSCAD

As someone not generally comfortable with CAD I've been enjoying the almost childlike simplicity of TinkerCAD. The other day, David, VK3KR, suggested I have a look at OpenSCAD. It is a very different approach. Rather than dragging shapes from a pallet and modifying them by dragging, you code the shapes you want.

I built a QRP L-Match some time ago, inspired by Peter VK3YE, but mounted in a small food storage box it didn't look great. Working in OpenSCAD looks like this:


You write code on the left and each time you save, the render updates on the right. Sometimes, I'd love it if I could drag something in the render and have the code update. Maybe one day. There's a button to export STL and it looks like it can talk to some 3D printers directly although I haven't tried this.

I particularly like that I can set variables and then use them throughout the code so changing things like the wall thickness is set once and updates everywhere.


My experience is about one day of playing so please don't take my code as a good example of best practice. Here it is though.

// Box for L match tuner

$fa = 1;    // Minimum angle

$fs = 0.4;  // Minimum size


wall_thickness = 1.5;

box_x=80;

box_y=65;

box_z=25;

overlap=0.001;

bnc_r=10.5/2;

bnc_holes=12.5/2;

switch_r=6.5/2;

poly_r=7/2;

poly_mount_r=3/2;

poly_mount_offset=7;


difference() {

    // Outer cube

    cube([box_x, box_y, box_z], center=true);

    

    // Inner cube (subtract from outer to create hollow space)

    // Inner dimensions: 20mm - 2*3mm = 14mm

    translate([0, 0, wall_thickness + overlap])

    cube([box_x-(2*wall_thickness), box_y-(2*wall_thickness), box_z-(wall_thickness)], center=true);

    

    bnc_socket(z=box_x / 2);

    bnc_socket(z=-box_x / 2);

    

    // inductance switch holes in side

    switch_spacing=10;

    for (i = [0:1:4]) {

        rotate([90,0,0])

        translate([(i * 10) - 20, 0, -box_y / 2]) // push to the side of the box

        cylinder(h=10, r1=switch_r, r2=switch_r, center=true);

    }

    

    // extra cap switch

    rotate([90,0,0])

    translate([0, 0, box_y / 2]) // push to the side of the box

    cylinder(h=10, r1=switch_r, r2=switch_r, center=true);

    

    translate([25,-15,0]) {

        // polyvaricon main hole

        rotate([0,0,90])

        translate([0, 0, -(box_z / 2)+4]) // push to the base of the box

        cylinder(h=10, r1=poly_r, r2=poly_r, center=true);

    

        // polyvaricon screw hole

        rotate([0,0,90])

        translate([poly_mount_offset, 0, -(box_z / 2)+4]) // push to the base of the box

        cylinder(h=10, r1=poly_mount_r, r2=poly_mount_r, center=true);

    

        // polyvaricon screw hole

        rotate([0,0,90])

        translate([-poly_mount_offset, 0, -(box_z / 2)+4]) // push to the base of the box

        cylinder(h=10, r1=poly_mount_r, r2=poly_mount_r, center=true);

    }

}


module bnc_socket(z = 0) {

// end hole for BNC socket

    rotate([0,90,0])

    translate([0, 0, z]) // push to the end of the box

    cylinder(h=10, r1=bnc_r, r2=bnc_r, center=true);

    

    // mounting holes for BNC socket

    rotate([0,90,0])

    translate([bnc_holes, bnc_holes, z]) // push to the end of the box

    cylinder(h=10, r1=poly_mount_r, r2=poly_mount_r, center=true);

    

    // mounting holes for BNC socket

    rotate([0,90,0])

    translate([-bnc_holes, bnc_holes, z]) // push to the end of the box

    cylinder(h=10, r1=poly_mount_r, r2=poly_mount_r, center=true);

    

    // mounting holes for BNC socket

    rotate([0,90,0])

    translate([bnc_holes, -bnc_holes, z]) // push to the end of the box

    cylinder(h=10, r1=poly_mount_r, r2=poly_mount_r, center=true);

    

    // mounting holes for BNC socket

    rotate([0,90,0])

    translate([-bnc_holes, -bnc_holes, z]) // push to the end of the box

    cylinder(h=10, r1=poly_mount_r, r2=poly_mount_r, center=true);

}

Here's the lid:

// Box lid for L match tuner

$fa = 1;    // Minimum angle

$fs = 0.4;  // Minimum size

wall_thickness = 1.5;

box_x=80;

box_y=65;

box_z=wall_thickness;

overlap=0.001;

// lid

cube([box_x, box_y, box_z]);

// inside

translate([wall_thickness, wall_thickness, 0])

cube([box_x-(wall_thickness*2), box_y-(wall_thickness*2), wall_thickness * 3]);

The language is a bit odd. I don't know why what I call functions are called modules for example.

There are some very interesting looking libraries available including one for project boxes called YAPP_box like mine. 

The downloadable binaries are quite old, dated 2021, but development seems active. I tried building the macOS version but it failed and I haven't persisted.

Although the learning curve on a code driven 3D design program is higher than a click and drag version there are benefits. Things like the row of holes for inductance switches is a loop and a single setting of the radius of the hole is used throughout.

No comments: