openscad Picatinny forward grip
openscad1c3d
Code
7,608 characters
// 4-Piece Collet-Lock Foregrip: Left Half, Right Half, Separate Recoil Bar, & Handle
$fn = 60;
/* [Display Mode] */
mode = 2; // 0 = Assembled, 1 = Exploded View, 2 = Print Bed Layout (All 4 Parts Flat)
/* [Mount Dimensions] */
mount_len = 42;
mount_width = 34;
mount_height = 16;
/* [Separate Recoil Key Specs] */
bar_width = 20.0; // Spans across rail channel into both halves
bar_thick = 5.0; // Fits MIL-STD-1913 slot (5.23mm nominal)
bar_height = 3.2; // Slot depth engagement
bar_tol = 0.20; // Clearance for sliding fit
/* [Thread & Conical Wedge Specs] */
thread_dia = 24.0;
thread_pitch = 4.0;
thread_len = 18.0;
shroud_height = 8.0;
shroud_outer_dia = 34.0;
thread_steps = 24;
wedge_dia_bottom = 27.5;
wedge_dia_top = 32.5;
/* [Fit Calibration] */
tol = 0.20;
split_gap = 1.0;
/* [Grip Dimensions] */
grip_h = 80;
grip_dia = 32;
flute_count = 16;
// -------------------------------------------------------------
// MIL-STD-1913 Picatinny Negative Channel
// -------------------------------------------------------------
module picatinny_channel(len) {
w_crown = 20.6 / 2;
w_neck = 15.0 / 2;
h_crown = 2.4;
h_bevel = 3.0;
rotate([90, 0, 0])
linear_extrude(height = len, center = true)
polygon(points = [
[-w_neck, 2.0],
[ w_neck, 2.0],
[ w_neck, -0.2],
[ w_crown, -0.2 - h_bevel],
[ w_crown, -0.2 - h_bevel - h_crown],
[-w_crown, -0.2 - h_bevel - h_crown],
[-w_crown, -0.2 - h_bevel],
[-w_neck, -0.2]
]);
}
// -------------------------------------------------------------
// Helical Thread Tool
// -------------------------------------------------------------
module helical_thread(dia, pitch, len, internal=false) {
total_deg = (len / pitch) * 360;
deg_step = 360 / thread_steps;
dz_step = pitch / thread_steps;
r_core = dia / 2 + (internal ? tol : 0);
h_ridge = 1.15;
for (a = [0 : deg_step : total_deg - deg_step]) {
z1 = (a / 360) * pitch;
z2 = z1 + dz_step;
hull() {
rotate([0, 0, a])
translate([r_core, 0, z1])
rotate([0, 90, 0])
cylinder(r1 = h_ridge, r2 = 0.2, h = 1.0, $fn = 4);
rotate([0, 0, a + deg_step])
translate([r_core, 0, z2])
rotate([0, 90, 0])
cylinder(r1 = h_ridge, r2 = 0.2, h = 1.0, $fn = 4);
}
}
}
// -------------------------------------------------------------
// Part 1 & 2: Symmetrical Mount Core Block
// -------------------------------------------------------------
module base_collet_solid() {
difference() {
union() {
// Main block
translate([0, 0, -mount_height / 2])
cube([mount_width, mount_len, mount_height], center = true);
// Conical clamping wedge
translate([0, 0, -mount_height - shroud_height])
cylinder(d1 = wedge_dia_bottom, d2 = wedge_dia_top, h = shroud_height);
// Male thread stem
translate([0, 0, -mount_height - shroud_height - thread_len])
cylinder(d = thread_dia - 2.2, h = thread_len);
// Helical threads
translate([0, 0, -mount_height - shroud_height - thread_len])
helical_thread(dia = thread_dia - 2.2, pitch = thread_pitch, len = thread_len, internal = false);
}
// Picatinny rail channel
picatinny_channel(mount_len + 4);
// Precision mortise pocket for the separate recoil bar
translate([0, 0, -3.2])
cube([bar_width + (bar_tol * 2), bar_thick + (bar_tol * 2), bar_height + (bar_tol * 2)], center = true);
}
}
module mount_half_left() {
difference() {
base_collet_solid();
translate([50 - split_gap/2, 0, -50])
cube([100, mount_len + 10, 150], center = true);
}
}
module mount_half_right() {
difference() {
base_collet_solid();
translate([-50 + split_gap/2, 0, -50])
cube([100, mount_len + 10, 150], center = true);
}
}
// -------------------------------------------------------------
// Part 3: Separate Removable Recoil Cross-Bar
// -------------------------------------------------------------
module separate_recoil_bar() {
chamfer = 0.6;
hull() {
translate([0, 0, 0])
cube([bar_width - chamfer*2, bar_thick - chamfer*2, bar_height], center = true);
translate([0, 0, 0])
cube([bar_width, bar_thick - chamfer*2, bar_height - chamfer*2], center = true);
}
}
// -------------------------------------------------------------
// Part 4: Matching Wedged Handle
// -------------------------------------------------------------
module solid_reinforced_handle() {
difference() {
rotate_extrude($fn = 60) {
polygon(points = [
[0, 0],
[grip_dia/2 + 2.5, 0],
[grip_dia/2 + 2.5, 6],
[grip_dia/2, 14],
[grip_dia/2, grip_h - 20],
[grip_dia/2 - 1.0, grip_h - 14],
[shroud_outer_dia/2, grip_h],
[0, grip_h]
]);
}
// Internal Conical Wedge Seat
translate([0, 0, grip_h - shroud_height - 0.1])
cylinder(d1 = wedge_dia_bottom + (tol * 2), d2 = wedge_dia_top + (tol * 2), h = shroud_height + 1);
// Thread Socket
translate([0, 0, grip_h - shroud_height - thread_len - 0.1])
cylinder(d = thread_dia + (tol * 2), h = thread_len + 1);
// Internal Threads
translate([0, 0, grip_h - shroud_height - thread_len])
helical_thread(dia = thread_dia, pitch = thread_pitch, len = thread_len - 2, internal = true);
// Flutes
for (i = [0 : flute_count - 1]) {
rotate([0, 0, i * (360 / flute_count)])
translate([grip_dia / 2, 0, (grip_h - shroud_height) / 2 - 2])
scale([0.9, 1.3, 1])
cylinder(d = 3.0, h = grip_h - shroud_height - 24, center = true, $fn = 16);
}
// Accent Ring
translate([0, 0, 10])
rotate_extrude()
translate([grip_dia / 2, 0, 0])
circle(r = 1.2, $fn = 16);
}
}
// -------------------------------------------------------------
// Visual Output Modes
// -------------------------------------------------------------
if (mode == 0) {
// Assembled View
mount_half_left();
mount_half_right();
color([0.85, 0.2, 0.2]) translate([0, 0, -3.2]) separate_recoil_bar();
translate([0, 0, -mount_height - grip_h]) solid_reinforced_handle();
}
else if (mode == 1) {
// Exploded View
translate([-14, 0, 0]) mount_half_left();
translate([14, 0, 0]) mount_half_right();
color([0.85, 0.2, 0.2]) translate([0, 0, 10]) separate_recoil_bar();
translate([0, 0, -mount_height - grip_h - 25]) solid_reinforced_handle();
}
else if (mode == 2) {
// All 4 Pieces Laid Completely Flat on Z = 0 for 3D Printing
// Left Half (Flat split-face down)
translate([-26, -20, 0])
rotate([0, 90, 0])
mount_half_left();
// Right Half (Flat split-face down)
translate([26, -20, 0])
rotate([0, -90, 0])
mount_half_right();
// Recoil Bar (Flat face down)
translate([0, -20, bar_thick / 2])
rotate([90, 0, 0])
separate_recoil_bar();
// Handle (Flat bottom pommel down)
translate([0, 25, 0])
solid_reinforced_handle();
}