// RemoteRig — Dual-ESP Tripod Case v3 // v3d changes: screw-tightened tripod clamp + horizontal two-screw mount + flush locating-lip lid. // 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; // Lid fit parameters lid_top_thick = 2.0; lid_lip_h = 1.6; lid_clearance = 0.6; // clearance around underside locating lip lid_lip_wall = 1.2; // thickness of perimeter lip/frame // 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 // Case ↔ clamp interface // v3b removes the dovetail: use a flat two-screw mounting plate instead. // This is simpler to print, easier to inspect, and field-serviceable. mount_plate_w = 24.0; mount_plate_h = 16.0; mount_plate_thick = 4.0; mount_hole_spacing = 14.0; // side-by-side M3 case-mount screws mount_screw_clear = 3.4; // M3 clearance through clamp plate mount_case_pilot = 2.7; // pilot/insert hole through case boss mount_boss_r = 1.2; // 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 case_mount_boss() { // Flat rear boss on the case. The clamp plate bolts directly to this face. // Holes run front/back (Y axis) for M3 screws, heat-set inserts, or nuts. boss_y = outer_d/2 + mount_plate_thick/2 - 0.2; difference() { translate([0, boss_y, outer_h/2]) rounded_cube_centered(mount_plate_w, mount_plate_thick, mount_plate_h, mount_boss_r); for (xoff = [-mount_hole_spacing/2, mount_hole_spacing/2]) { translate([xoff, outer_d/2 + mount_plate_thick/2, outer_h/2]) rotate([90, 0, 0]) cylinder(d=mount_case_pilot, h=mount_plate_thick + wall*3, center=true, $fn=24); } } } 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)); case_mount_boss(); } } module lid_locating_lip() { // Thin underside frame that drops into the case opening. This registers the // lid so it cannot skate/rock on the rim, while staying clear of screw posts. lip_outer_w = inner_w + tol - lid_clearance; lip_outer_d = inner_d + tol - lid_clearance; lip_inner_w = lip_outer_w - lid_lip_wall*2; lip_inner_d = lip_outer_d - lid_lip_wall*2; translate([0, 0, -lid_lip_h]) difference() { rounded_cube0(lip_outer_w, lip_outer_d, lid_lip_h, 1.0); translate([0, 0, -0.1]) rounded_cube0(lip_inner_w, lip_inner_d, lid_lip_h + 0.2, 0.7); // Corner reliefs so the lip doesn't interfere with screw posts. for (x = [-1, 1], y = [-1, 1]) { translate([x*(outer_w/2 - 5), y*(outer_d/2 - 5), lid_lip_h/2]) cylinder(d=7.0, h=lid_lip_h + 0.4, center=true, $fn=24); } } } module case_lid() { difference() { union() { // Thinner top cover; underside lip handles registration. rounded_cube0(outer_w, outer_d, lid_top_thick, 0.8); lid_locating_lip(); } for (x = [-1, 1], y = [-1, 1]) { translate([x*(outer_w/2 - 5), y*(outer_d/2 - 5), -lid_lip_h - 0.5]) cylinder(d=2.4, h=lid_top_thick + lid_lip_h + 1, center=false, $fn=20); } for (x = [-outer_w/4, 0, outer_w/4]) { translate([x, 0, lid_top_thick/2]) cube([8, outer_d*0.6, lid_top_thick*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 + tol, 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 clamp_mount_plate() { outer_r = pole_dia/2 + clamp_thick; plate_y = -outer_r - mount_plate_thick/2 + 0.2; // Flat plate matching the case boss. Two M3 clearance holes pass through // along Y so the clamp bolts to the case with ordinary hardware. difference() { translate([0, plate_y, 0]) rounded_cube_centered(mount_plate_w, mount_plate_thick, mount_plate_h, mount_boss_r); for (xoff = [-mount_hole_spacing/2, mount_hole_spacing/2]) { translate([xoff, plate_y, 0]) rotate([90, 0, 0]) cylinder(d=mount_screw_clear, h=mount_plate_thick + 2, center=true, $fn=24); } } } module tripod_clamp() { union() { clamp_ring_with_mouth(); clamp_ears(); clamp_mount_plate(); } } // Backward-compatible alias for earlier export scripts. module tripod_clip() { tripod_clamp(); } module full_case() { case_body(); translate([0, 0, outer_h]) case_lid(); translate([0, outer_d/2 + pole_dia/2 + clamp_thick + 8, outer_h/2]) rotate([90, 0, 0]) tripod_clamp(); }