generated from CubeCraft-Creations/Tracehound
feat: redesigned case — tripod-clip box for dual ESPs, USB power bank
Replaced GoPro-sleeve case design with simpler stand-mounted box: - Case clips to tripod leg/stand pole (20-35mm diameter) - No camera sleeve needed — case sits on the stand - Powered by standard USB power bank (off-the-shelf) - Holds ESP8266 + ESP32 stacked with UART wiring - Cable ports for USB in/out, LED window, ventilation Simplified BOM: ~1/node (down from 4), no buck converters needed
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user