// RemoteRig — Dual-ESP Tripod Case // ================================= // Small box that clips onto a tripod leg or light stand pole. // Holds ESP8266 D1 Mini + ESP32 Dev Board (stacked). // Powered by standard USB battery pack. No camera sleeve needed. // // Print settings: // Material: PETG | Layer: 0.2mm | Infill: 20% gyroid // Supports: yes (for clip overhang) | Brim: 5mm // ── 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; // air gap between stacked boards 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; outer_d = inner_d + wall*2 + tol*2; outer_h = inner_h + wall*2; // ── Tripod clip parameters ── pole_min_dia = 20; // smallest pole pole_max_dia = 35; // largest pole clip_width = 12; // clip width clip_thick = 3; // clip arm thickness clip_grip = 2; // grip ridges // ── Cable ports ── usb_port_w = 12; usb_port_h = 6; uart_port_w = 6; uart_port_h = 4; // ══════════════════════════════════════════════════════════════ // MAIN — render the full case // ══════════════════════════════════════════════════════════════ // Uncomment to render individual parts: full_case(); // case_body(); // case_lid(); // tripod_clip(); module full_case() { case_body(); // Lid positioned above (for visualization) translate([0, 0, outer_h + 2]) case_lid(); // Clip on the back translate([0, outer_d/2 + pole_max_dia/2 + clip_thick, outer_h/2]) tripod_clip(); } // ══════════════════════════════════════════════════════════════ // Case Body — holds both boards, cable ports // ══════════════════════════════════════════════════════════════ module case_body() { difference() { // Outer shell rounded_cube(outer_w, outer_d, outer_h, 3); // Inner cavity translate([0, 0, wall]) rounded_cube(inner_w + tol, inner_d + tol, inner_h + tol, 2); // ── Board recesses ── // Bottom: ESP32 (larger board) translate([0, 0, wall + 1]) cube([esp32_w + tol, esp32_d + tol, esp32_h + 1], center=true); // Top: ESP8266 (smaller board) translate([0, 0, wall + esp32_h + board_gap + 1]) cube([esp8266_w + tol, esp8266_d + tol, esp8266_h + 1], center=true); // ── Cable ports ── // USB power IN (from battery pack → ESP32) translate([0, outer_d/2, outer_h/3]) cube([usb_port_w, wall*3, usb_port_h], center=true); // USB power OUT (from battery pack → GoPro) translate([0, -outer_d/2, outer_h/3]) cube([usb_port_w, wall*3, usb_port_h], center=true); // UART wire channel (ESP8266 → ESP32 internal) translate([outer_w/2, 0, outer_h/2]) cube([wall*3, uart_port_w, uart_port_h], center=true); // ── Ventilation slots (top edge) ── for (x = [-outer_w/4, 0, outer_w/4]) { translate([x, 0, outer_h - wall]) cube([8, outer_d*0.6, 2], center=true); } // ── Screw posts for lid ── for (x = [-1, 1], y = [-1, 1]) { translate([x*(outer_w/2 - 5), y*(outer_d/2 - 5), outer_h/2]) cylinder(d=3.2, h=outer_h, center=true, $fn=16); } // ── LED window (thin spot to see board LEDs) ── translate([-outer_w/4, -outer_d/2, wall]) cube([6, 1, 3], center=true); } // ── Tripod clip mount (rail on back) ── translate([0, outer_d/2, outer_h/2]) rotate([90, 0, 0]) difference() { cube([clip_width + 4, outer_h*0.7, 6], center=true); // T-slot for clip to slide in cube([clip_width + 1, outer_h*0.7 + 1, 4], center=true); } } // ══════════════════════════════════════════════════════════════ // Case Lid — snap-fit or screw-on cover // ══════════════════════════════════════════════════════════════ module case_lid() { difference() { rounded_cube(outer_w, outer_d, wall*2, 2); // Screw holes (match body posts) for (x = [-1, 1], y = [-1, 1]) { translate([x*(outer_w/2 - 5), y*(outer_d/2 - 5), 0]) cylinder(d=3.2, h=wall*3, center=true, $fn=16); } // Ventilation slots (match body) for (x = [-outer_w/4, 0, outer_w/4]) { translate([x, 0, 0]) cube([8, outer_d*0.6, 3], center=true); } } } // ══════════════════════════════════════════════════════════════ // Tripod Clip — C-clamp for pole mounting // ══════════════════════════════════════════════════════════════ module tripod_clip() { difference() { union() { // Main body hull() { translate([0, -pole_max_dia/2 - clip_thick, 0]) cube([clip_width, clip_thick*2, outer_h*0.7], center=true); translate([0, pole_max_dia/2 + clip_thick, 0]) cube([clip_width, clip_thick*2, outer_h*0.7], center=true); } // Top arm (flexible) translate([0, -pole_max_dia/2 - clip_thick, outer_h*0.35]) cube([clip_width, pole_max_dia + clip_thick*4, clip_thick], center=true); // Bottom arm translate([0, -pole_max_dia/2 - clip_thick, -outer_h*0.35]) cube([clip_width, pole_max_dia + clip_thick*4, clip_thick], center=true); // Mounting tab (slides into case rail) translate([0, -pole_max_dia/2 - clip_thick*3, 0]) cube([clip_width + 1, clip_thick*2, outer_h*0.7], center=true); } // Pole hole cylinder(d=pole_max_dia + 2, h=outer_h*1.5, center=true, $fn=32); // Grip ridges on inner surface for (z = [-outer_h*0.25, 0, outer_h*0.25]) { translate([0, 0, z]) rotate_extrude(angle=180, $fn=32) translate([pole_max_dia/2 + 0.5, 0]) circle(d=1); } // Entry slot (pole slides in from front) translate([0, pole_max_dia/2 + clip_thick, 0]) cube([clip_width + 2, pole_max_dia + 10, outer_h*0.7], center=true); } } // ══════════════════════════════════════════════════════════════ // Utility: rounded cube // ══════════════════════════════════════════════════════════════ module rounded_cube(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=20); } } }