OpenScad Bolt Config

Sep 8, 2026 3:26am · 29 views
openscad1c3d
Code 17,663 characters
/* Metric / Standard sizes , hex nut, wing nut. Everything has options */

/* [Size & Standard Selection] */
bolt_size           = "M8"; // [M3, M4, M5, M6, M8, M10, M12, M16, #6: "#6 (0.138 in)", #8: "#8 (0.164 in)", #10: "#10 (0.190 in)", 1/4: "1/4 in", 5/16: "5/16 in", 3/8: "3/8 in", 1/2: "1/2 in"]
thread_standard     = "iso60"; // [iso60: Standard 60-Deg V-Thread, trapezoidal: Trapezoidal / ACME Style (Cleaner 3D Printing)]
thread_type         = "coarse"; // [coarse: Standard / Coarse, fine: Fine]

/* [Bolt Dimensions & Profile] */
metric_length_mm    = 30.0; // [5:1:150]
imperial_length_in  = 1.25; // [0.25:0.125:6.0]
unthreaded_shank    = 8.0;  // Length of smooth unthreaded grip/shoulder under head (mm)
head_type           = "socket_cap"; // [hex: Standard Hex, hex_flanged: Flanged Hex Head, socket_cap: Socket Cap (Allen), pan_phillips: Pan Head (Phillips), flat_countersunk: Countersunk Flat, carriage: Carriage Bolt (Square Neck)]

/* [Nut Configuration] */
nut_type            = "standard_hex"; // [standard_hex: Regular Hex Nut, wing: Wing Nut, cap: Domed Cap / Nyloc Style, thumb: Knurled Thumb Nut]

/* [Washer Configuration] */
washer_type         = "standard_flat"; // [standard_flat: Flat Washer, belleville: Belleville / Conical Spring, split_lock: Split-Ring Lock Washer]

/* [Printability & Mechanical Enhancements] */
enable_print_flat   = false; // Shaves a flat face along one side of bolt for horizontal printing (5x tensile strength)
enable_lead_in      = true;  // 45-deg chamfer on bolt tip and nut entry for smooth starting
enable_fillets      = true;  // Stress-relief fillet under bolt head & thread relief undercut
enable_efoot_bevel  = true;  // 45-deg bevel at bed interface to counteract elephant foot squish

/* [Included Parts] */
include_bolt        = true;
include_nut         = true;
include_washer      = true;

/* [Tolerances & Quality] */
thread_clearance    = 0.35; // Internal thread clearance in mm (0.3 - 0.45 recommended)
steps_per_turn      = 36;   // Angular smoothness of helix
$fn                 = 50;   // Smoothness for cylinders

// ========================================================
// Unified Lookup Specification Table
// ========================================================

spec_table = [
    // Key,  Sys, Dia,     P_crs,    P_fn,     Hex_AF,     Head_H,     Wash_OD,    Wash_T
    ["M3",   0,   3.0,     0.50,     0.35,      5.5,       2.0,         7.0,       0.5],
    ["M4",   0,   4.0,     0.70,     0.50,      7.0,       2.8,         9.0,       0.8],
    ["M5",   0,   5.0,     0.80,     0.50,      8.0,       3.5,        10.0,       1.0],
    ["M6",   0,   6.0,     1.00,     0.75,     10.0,       4.0,        12.0,       1.6],
    ["M8",   0,   8.0,     1.25,     1.00,     13.0,       5.3,        16.0,       1.6],
    ["M10",  0,  10.0,     1.50,     1.25,     16.0,       6.4,        20.0,       2.0],
    ["M12",  0,  12.0,     1.75,     1.25,     18.0,       7.5,        24.0,       2.5],
    ["M16",  0,  16.0,     2.00,     1.50,     24.0,      10.0,        30.0,       3.0],

    ["#6",   1,   0.138*25.4, 25.4/32, 25.4/40,  5/16*25.4, 3/32*25.4,   3/8*25.4,   0.049*25.4],
    ["#8",   1,   0.164*25.4, 25.4/32, 25.4/36, 11/32*25.4, 7/64*25.4,   7/16*25.4,  0.049*25.4],
    ["#10",  1,   0.190*25.4, 25.4/24, 25.4/32,  3/8*25.4,  1/8*25.4,    1/2*25.4,   0.063*25.4],
    ["1/4",  1,   0.250*25.4, 25.4/20, 25.4/28,  7/16*25.4, 5/32*25.4,   5/8*25.4,   0.065*25.4],
    ["5/16", 1,   0.3125*25.4,25.4/18, 25.4/24,  1/2*25.4,  13/64*25.4,  11/16*25.4, 0.065*25.4],
    ["3/8",  1,   0.375*25.4, 25.4/16, 25.4/24,  9/16*25.4, 15/64*25.4,  13/16*25.4, 0.065*25.4],
    ["1/2",  1,   0.500*25.4, 25.4/13, 25.4/20,  3/4*25.4,  5/16*25.4,   1.062*25.4, 0.095*25.4]
];

function get_specs(match_str) = 
    spec_table[search([match_str], spec_table, num_returns_per_match=1, index_col_num=0)[0]];

row = get_specs(bolt_size);

is_imperial     = (row[1] == 1);
d_nominal       = row[2];
pitch           = (thread_type == "coarse") ? row[3] : row[4];
hex_af          = row[4];
head_h          = row[6];
washer_od       = row[7];
washer_thk      = row[8];
nut_h           = head_h * 1.25;

raw_len         = is_imperial ? (imperial_length_in * 25.4) : metric_length_mm;
shoulder_len    = min(unthreaded_shank, raw_len - (pitch * 3));
thread_len      = raw_len - shoulder_len;

spacing         = max(d_nominal * 3.5, hex_af * 2.2, washer_od * 1.3);

// ========================================================
// Scene Assembly
// ========================================================

if (include_bolt) {
    if (enable_print_flat) {
        // Lay bolt horizontal on sliced flat face
        translate([0, 0, (d_nominal / 2) - 0.5])
            rotate([90, 0, 0])
                bolt();
    } else {
        bolt();
    }
}

if (include_nut) {
    translate([spacing, 0, 0])
        nut();
}

if (include_washer) {
    translate([-spacing, 0, 0])
        washer();
}

// ========================================================
// Bolt Generator
// ========================================================

module bolt() {
    difference() {
        union() {
            bolt_head();
            
            // Smooth shoulder / unthreaded grip
            if (shoulder_len > 0) {
                cylinder(d = d_nominal, h = shoulder_len);
            }
            
            // Threaded Segment
            translate([0, 0, shoulder_len]) {
                // Thread relief undercut
                if (enable_fillets) {
                    cylinder(d = d_nominal - (pitch * 0.9), h = pitch * 0.8);
                }
                
                difference() {
                    union() {
                        // Solid core
                        cylinder(d = d_nominal - (pitch * 0.85), h = thread_len);
                        
                        // Solid thread profile
                        screw_thread(
                            d = d_nominal, 
                            pitch = pitch, 
                            length = thread_len, 
                            clearance = 0, 
                            internal = false, 
                            steps = steps_per_turn,
                            trap = (thread_standard == "trapezoidal")
                        );
                    }
                    
                    // 45-degree tip lead-in chamfer
                    if (enable_lead_in) {
                        translate([0, 0, thread_len])
                            difference() {
                                cylinder(d = d_nominal * 1.5, h = pitch * 1.5);
                                cylinder(d1 = d_nominal, d2 = d_nominal - (pitch * 2), h = pitch);
                            }
                    }
                }
            }
            
            // Stress relief fillet at head/shank junction
            if (enable_fillets) {
                cylinder(d1 = d_nominal + (pitch * 0.6), d2 = d_nominal, h = pitch * 0.4);
            }
        }
        
        // Horizontal Print Flat (removes tiny slice for bed adhesion when printing flat)
        if (enable_print_flat) {
            translate([-spacing, -(d_nominal + 20), -head_h * 2])
                cube([spacing * 2, 20 + (d_nominal / 2) - 0.5, raw_len + head_h * 4]);
        }
    }
}

// ========================================================
// Bolt Head Styles
// ========================================================

module bolt_head() {
    difference() {
        bolt_head_solid();
        
        // Elephant foot compensation bevel on head bottom
        if (enable_efoot_bevel) {
            translate([0, 0, -head_h - 0.1])
                difference() {
                    cylinder(d = hex_af * 2, h = 0.5);
                    cylinder(d1 = (hex_af * 0.9) - 0.6, d2 = hex_af * 0.9, h = 0.5);
                }
        }
    }
}

module bolt_head_solid() {
    if (head_type == "hex") {
        translate([0, 0, -head_h])
            rotate([0, 0, 30])
                cylinder(r = (hex_af / 2) / cos(30), h = head_h, $fn = 6);
                
    } else if (head_type == "hex_flanged") {
        flange_d = hex_af * 1.35;
        flange_h = head_h * 0.3;
        translate([0, 0, -head_h]) {
            cylinder(d = flange_d, h = flange_h);
            rotate([0, 0, 30])
                cylinder(r = (hex_af / 2) / cos(30), h = head_h, $fn = 6);
        }
        
    } else if (head_type == "socket_cap") {
        cap_h = d_nominal;
        cap_d = d_nominal * 1.5;
        allen_size = d_nominal * 0.75;
        socket_depth = cap_h * 0.6;
        
        translate([0, 0, -cap_h])
            difference() {
                cylinder(d = cap_d, h = cap_h);
                // Hex socket with conical self-supporting bridge ceiling
                translate([0, 0, -0.1])
                    cylinder(r = (allen_size / 2) / cos(30), h = socket_depth + 0.1, $fn = 6);
                translate([0, 0, socket_depth - 0.1])
                    cylinder(r1 = (allen_size / 2) / cos(30), r2 = 0, h = allen_size * 0.5, $fn = 6);
            }
            
    } else if (head_type == "pan_phillips") {
        pan_h = d_nominal * 0.65;
        pan_d = d_nominal * 2.0;
        recess_depth = pan_h * 0.65;
        recess_w = d_nominal * 0.28;
        recess_l = d_nominal * 1.15;
        
        translate([0, 0, -pan_h])
            difference() {
                cylinder(d1 = pan_d * 0.85, d2 = pan_d, h = pan_h);
                translate([0, 0, -0.1]) {
                    phillips_slot(recess_l, recess_w, recess_depth);
                    rotate([0, 0, 90])
                        phillips_slot(recess_l, recess_w, recess_depth);
                }
            }
            
    } else if (head_type == "flat_countersunk") {
        flat_d = d_nominal * 2.0;
        allen_size = d_nominal * 0.6;
        socket_depth = head_h * 0.6;
        
        translate([0, 0, -head_h])
            difference() {
                cylinder(d1 = flat_d, d2 = d_nominal, h = head_h);
                translate([0, 0, -0.1])
                    cylinder(r = (allen_size / 2) / cos(30), h = socket_depth + 0.1, $fn = 6);
            }
            
    } else if (head_type == "carriage") {
        dome_d = d_nominal * 2.2;
        dome_h = d_nominal * 0.6;
        neck_sq = d_nominal * 0.95;
        neck_h = d_nominal * 0.45;
        
        translate([0, 0, -(dome_h + neck_h)]) {
            // Smooth round dome
            intersection() {
                sphere(d = dome_d);
                translate([0, 0, dome_d * 0.15])
                    cylinder(d = dome_d, h = dome_h);
            }
            // Square locking neck
            translate([0, 0, dome_h])
                cube([neck_sq, neck_sq, neck_h * 2], center = true);
        }
    }
}

module phillips_slot(length, width, depth) {
    linear_extrude(height = depth + 0.2, scale = [0.65, 0.4])
        square([length, width], center = true);
}

// ========================================================
// Nut Geometries
// ========================================================

module nut() {
    difference() {
        nut_outer_body();
        
        // Inner clearance core
        translate([0, 0, -1])
            cylinder(d = d_nominal - (pitch * 0.85) + (thread_clearance * 2), h = nut_h * 2 + 2);
            
        // Internal Thread
        translate([0, 0, -0.5])
            screw_thread(
                d = d_nominal, 
                pitch = pitch, 
                length = nut_h + 1.0, 
                clearance = thread_clearance, 
                internal = true, 
                steps = steps_per_turn,
                trap = (thread_standard == "trapezoidal")
            );
            
        // 45-degree entry and exit lead-in chamfers
        if (enable_lead_in) {
            translate([0, 0, -0.1])
                cylinder(d1 = d_nominal + 1.0, d2 = d_nominal - 1.0, h = 1.0);
            translate([0, 0, nut_h - 0.9])
                cylinder(d1 = d_nominal - 1.0, d2 = d_nominal + 1.0, h = 1.0);
        }
        
        // Elephant-foot bevel on nut base
        if (enable_efoot_bevel) {
            translate([0, 0, -0.1])
                difference() {
                    cylinder(d = hex_af * 2, h = 0.5);
                    cylinder(d1 = (hex_af * 0.9) - 0.6, d2 = hex_af * 0.9, h = 0.5);
                }
        }
    }
}

module nut_outer_body() {
    if (nut_type == "standard_hex") {
        rotate([0, 0, 30])
            cylinder(r = (hex_af / 2) / cos(30), h = nut_h, $fn = 6);
            
    } else if (nut_type == "wing") {
        wing_span = d_nominal * 4.0;
        wing_thick = d_nominal * 0.45;
        wing_h = nut_h * 1.6;
        union() {
            cylinder(d = hex_af, h = nut_h);
            hull() {
                translate([-(wing_span / 2) + (wing_thick / 2), 0, wing_h * 0.7])
                    sphere(d = wing_thick);
                translate([(wing_span / 2) - (wing_thick / 2), 0, wing_h * 0.7])
                    sphere(d = wing_thick);
                cylinder(d = hex_af * 0.9, h = nut_h * 0.5);
            }
        }
        
    } else if (nut_type == "cap") {
        union() {
            rotate([0, 0, 30])
                cylinder(r = (hex_af / 2) / cos(30), h = nut_h, $fn = 6);
            translate([0, 0, nut_h])
                sphere(r = (hex_af / 2) / cos(30) * 0.85);
        }
        
    } else if (nut_type == "thumb") {
        thumb_d = max(d_nominal * 2.6, 18);
        num_grooves = 24;
        difference() {
            cylinder(d = thumb_d, h = nut_h);
            for (i = [0:num_grooves - 1]) {
                rotate([0, 0, i * (360 / num_grooves)])
                    translate([thumb_d / 2, 0, -0.5])
                        cylinder(d = thumb_d * 0.12, h = nut_h + 1);
            }
        }
    }
}

// ========================================================
// Washer Module (Flat, Belleville, Split-Lock)
// ========================================================

module washer() {
    hole_dia = d_nominal + (thread_clearance * 2.5);
    
    if (washer_type == "standard_flat") {
        difference() {
            cylinder(d = washer_od, h = washer_thk);
            translate([0, 0, -1])
                cylinder(d = hole_dia, h = washer_thk + 2);
        }
    } else if (washer_type == "belleville") {
        // Conical Spring Washer
        cone_h = washer_thk * 1.7;
        difference() {
            cylinder(d1 = washer_od, d2 = washer_od * 0.9, h = cone_h);
            translate([0, 0, -0.5])
                cylinder(d1 = hole_dia, d2 = hole_dia * 0.95, h = cone_h + 1);
            translate([0, 0, -0.5])
                cylinder(d1 = washer_od * 0.85, d2 = 0, h = cone_h * 0.9);
        }
    } else if (washer_type == "split_lock") {
        // Helical Split Lock Washer
        pitch_split = washer_thk * 0.8;
        difference() {
            linear_extrude(height = washer_thk + pitch_split, twist = 340, slices = 40)
                translate([hole_dia / 2, 0, 0])
                    square([(washer_od - hole_dia) / 2, washer_thk]);
            // Split gap cut
            rotate([0, 0, 10])
                translate([0, 0, -1])
                    cube([washer_od, washer_thk * 0.4, washer_thk * 3]);
        }
    }
}

// ========================================================
// Solid Polyhedron Thread Engine (ISO 60 & Trapezoidal)
// ========================================================

module screw_thread(d, pitch, length, clearance=0, internal=false, steps=36, trap=false) {
    turns = ceil(length / pitch) + 1;
    total_steps = turns * steps;
    dz = pitch / steps;
    da = 360 / steps;
    
    H = pitch * cos(30);
    r_nom = d / 2;
    
    r_crest = internal ? (r_nom + clearance) : (r_nom);
    r_root  = internal ? (r_nom - (0.65 * H)) : (r_nom - (0.65 * H) - clearance);

    // Profile offsets: Trapezoidal gives flattened, overhang-friendly 30-deg flanks
    crest_lead = trap ? 0.30 : 0.35;
    crest_lag  = trap ? 0.45 : 0.35;
    top_lead   = trap ? 0.75 : 0.70;

    intersection() {
        cylinder(r = r_crest + 2, h = length);

        polyhedron(
            points = [
                for (i = [0:total_steps])
                    let (
                        a = i * da,
                        z = i * dz,
                        p_root_bot = [r_root * cos(a),  r_root * sin(a),  z],
                        p_crest_1  = [r_crest * cos(a), r_crest * sin(a), z + (pitch * crest_lead)],
                        p_crest_2  = [r_crest * cos(a), r_crest * sin(a), z + (pitch * crest_lag)],
                        p_root_top = [r_root * cos(a),  r_root * sin(a),  z + (pitch * top_lead)]
                    )
                    each [p_root_bot, p_crest_1, p_crest_2, p_root_top]
            ],
            faces = [
                for (i = [0:total_steps - 1])
                    let (base = i * 4)
                    each [
                        // Lower flank
                        [base,     base + 1, base + 5],
                        [base,     base + 5, base + 4],
                        // Crest flat/ridge
                        [base + 1, base + 2, base + 6],
                        [base + 1, base + 6, base + 5],
                        // Upper flank
                        [base + 2, base + 3, base + 7],
                        [base + 2, base + 7, base + 6],
                        // Root boundary
                        [base + 3, base,     base + 4],
                        [base + 3, base + 4, base + 7]
                    ]
            ],
            convexity = 10
        );
    }
}