Files
remote-rig/hardware/case/tripod-case-v3.scad
T

202 lines
6.3 KiB
OpenSCAD
Raw Normal View History

// RemoteRig — Dual-ESP Tripod Case v3
// v3 changes: screw-tightened tripod clamp + dovetail slide interface.
// Coordinate system: all case/lid geometry uses bottom-origin Z.
$fn = 36;
// Board dimensions
esp8266_w = 34.2; esp8266_d = 25.6; esp8266_h = 5;
esp32_w = 52; esp32_d = 28; esp32_h = 5;
board_gap = 3;
stack_h = esp8266_h + esp32_h + board_gap;
inner_w = max(esp8266_w, esp32_w);
inner_d = max(esp8266_d, esp32_d);
inner_h = stack_h + 2;
// Case parameters
wall = 2.0;
tol = 0.4;
outer_w = inner_w + wall*2 + tol*2; // 56.8mm
outer_d = inner_d + wall*2 + tol*2; // 32.8mm
outer_h = inner_h + wall*2; // 19mm
corner_r = 2.5;
// Tripod clamp parameters
pole_dia = 35; // nominal stand/pole diameter
clamp_thick = 4.0; // ring wall thickness
clamp_width = 16.0; // extrusion width along Z
mouth_width = 13.0; // clamp opening
m3_clearance = 3.4; // M3 screw clearance
nut_flat = 6.4; // M3 nut trap flat-to-flat
// Dovetail interface
rail_z = outer_h * 0.78;
rail_depth = 5.0;
rail_open_w = 12.0;
rail_back_w = 18.0;
rail_clearance = 0.35;
// Cable ports
usb_port_w = 12; usb_port_h = 6;
uart_port_w = 6; uart_port_h = 4;
// Uncomment one for manual OpenSCAD use
// full_case();
// case_body();
// case_lid();
// tripod_clamp();
module rounded_cube_centered(w, d, h, r) {
hull() {
for (x = [-1, 1], y = [-1, 1], z = [-1, 1]) {
translate([x*(w/2 - r), y*(d/2 - r), z*(h/2 - r)])
sphere(r=r, $fn=24);
}
}
}
module rounded_cube0(w, d, h, r) {
translate([0, 0, h/2]) rounded_cube_centered(w, d, h, r);
}
module hex_prism(d, h) {
cylinder(d=d, h=h, center=true, $fn=6);
}
module dovetail_prism(length_z, front_w, back_w, depth) {
// 2D profile is X/Y, extruded along Z.
rotate([0, 0, 0])
linear_extrude(height=length_z, center=true, convexity=10)
polygon(points=[
[-front_w/2, 0], [front_w/2, 0],
[back_w/2, depth], [-back_w/2, depth]
]);
}
module case_shell() {
difference() {
rounded_cube0(outer_w, outer_d, outer_h, corner_r);
// Open internal cavity: starts above bottom wall, extends past top.
translate([0, 0, wall])
rounded_cube0(inner_w + tol, inner_d + tol, outer_h + 2, 1.6);
// USB power IN / OUT ports through front/back walls.
translate([0, outer_d/2 + 0.1, wall + 4])
cube([usb_port_w, wall*3, usb_port_h], center=true);
translate([0, -outer_d/2 - 0.1, wall + 4])
cube([usb_port_w, wall*3, usb_port_h], center=true);
// UART side channel.
translate([outer_w/2 + 0.1, 0, wall + 6])
cube([wall*3, uart_port_w, uart_port_h], center=true);
// LED viewing window on front lower wall.
translate([-outer_w/4, -outer_d/2 - 0.1, wall + 2])
cube([6, wall*2, 3], center=true);
}
}
module screw_post(x, y) {
difference() {
translate([x, y, wall]) cylinder(d=5.0, h=outer_h-wall-0.5, center=false, $fn=24);
translate([x, y, wall-0.5]) cylinder(d=2.1, h=outer_h+1, center=false, $fn=20);
}
}
module dovetail_socket_rails() {
// Female-ish dovetail receiver on the case back. The clamp's male dovetail slides vertically.
// Two angled lips are intentionally proud of the rear wall for printability and strength.
for (side = [-1, 1]) {
translate([side*(rail_open_w/2 + 1.3), outer_d/2 + 0.9, outer_h/2])
rotate([0, 0, side*8])
cube([3.0, rail_depth + 1.0, rail_z], center=true);
}
// Bottom stop so clamp cannot slide all the way through.
translate([0, outer_d/2 + 1.3, outer_h*0.12])
cube([rail_back_w + 2, rail_depth, 2.4], center=true);
}
module case_body() {
union() {
case_shell();
for (x = [-1, 1], y = [-1, 1])
screw_post(x*(outer_w/2 - 5), y*(outer_d/2 - 5));
dovetail_socket_rails();
}
}
module case_lid() {
difference() {
rounded_cube0(outer_w, outer_d, wall*2, 1.8);
for (x = [-1, 1], y = [-1, 1]) {
translate([x*(outer_w/2 - 5), y*(outer_d/2 - 5), -0.5])
cylinder(d=2.4, h=wall*2 + 1, center=false, $fn=20);
}
for (x = [-outer_w/4, 0, outer_w/4]) {
translate([x, 0, wall*2/2])
cube([8, outer_d*0.6, wall*3], center=true);
}
}
}
module clamp_ring_with_mouth() {
outer_r = pole_dia/2 + clamp_thick;
difference() {
cylinder(r=outer_r, h=clamp_width, center=true, $fn=72);
cylinder(r=pole_dia/2 + rail_clearance, h=clamp_width + 1, center=true, $fn=72);
// Mouth opens toward +Y. Width is intentionally generous for snap-on placement before tightening.
translate([0, outer_r, 0])
cube([mouth_width, outer_r*2, clamp_width + 2], center=true);
}
}
module clamp_ears() {
outer_r = pole_dia/2 + clamp_thick;
ear_y = outer_r + 2.2;
ear_z = 0;
difference() {
union() {
translate([-mouth_width/2 - 3.2, ear_y, ear_z])
rounded_cube_centered(7.0, 9.0, clamp_width, 1.4);
translate([ mouth_width/2 + 3.2, ear_y, ear_z])
rounded_cube_centered(7.0, 9.0, clamp_width, 1.4);
}
// M3 screw passes across the mouth along X.
translate([0, ear_y, ear_z])
rotate([0, 90, 0]) cylinder(d=m3_clearance, h=mouth_width + 24, center=true, $fn=24);
// Nut trap on the right ear.
translate([mouth_width/2 + 3.2, ear_y, ear_z])
rotate([0, 90, 0]) hex_prism(nut_flat, 4.2);
}
}
module male_dovetail_tab() {
outer_r = pole_dia/2 + clamp_thick;
// Tab on rear of clamp, opposite the mouth. Slides into case rails.
translate([0, -outer_r - rail_depth + 0.4, 0])
dovetail_prism(clamp_width, rail_open_w - rail_clearance, rail_back_w - rail_clearance, rail_depth);
}
module tripod_clamp() {
union() {
clamp_ring_with_mouth();
clamp_ears();
male_dovetail_tab();
}
}
// Backward-compatible alias for earlier export scripts.
module tripod_clip() {
tripod_clamp();
}
module full_case() {
case_body();
translate([0, 0, outer_h + 2]) case_lid();
translate([0, outer_d/2 + pole_dia/2 + clamp_thick + 8, outer_h/2])
rotate([90, 0, 0]) tripod_clamp();
}