OpenScad Bolt Config
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
);
}
}