generated from CubeCraft-Creations/Tracehound
259 lines
9.1 KiB
OpenSCAD
259 lines
9.1 KiB
OpenSCAD
// RemoteRig — Dual-ESP Tripod Case v3
|
|
// v3e changes: board-specific envelope for ESP32-C3 Super Mini + ESP-01S with wiring clearance.
|
|
// Coordinate system: all case/lid geometry uses bottom-origin Z.
|
|
|
|
$fn = 36;
|
|
|
|
// Board dimensions from selected modules.
|
|
// ESP32-C3 Super Mini: 22.5 x 18.0 mm footprint.
|
|
// ESP-01S / ESP8266: 24.7 x 14.3 x 12.0 mm envelope.
|
|
// The case is intentionally larger than board footprints because the field
|
|
// build needs room for Dupont/UART wiring, power leads, bend radius, and fingers.
|
|
esp32c3_w = 22.5; esp32c3_d = 18.0; esp32c3_h = 6.0; // height allowance includes headers/pins TBD
|
|
esp01s_w = 24.7; esp01s_d = 14.3; esp01s_h = 12.0;
|
|
board_gap = 8.0; // side-by-side service gap between boards
|
|
wire_x = 8.0; // wiring gutter at left/right ends
|
|
wire_y = 8.0; // wiring gutter along front/back edges
|
|
wire_z = 10.0; // vertical wiring/connector clearance above tallest module
|
|
|
|
inner_w = esp32c3_w + esp01s_w + board_gap + wire_x*2;
|
|
inner_d = max(esp32c3_d, esp01s_d) + wire_y*2;
|
|
inner_h = max(esp32c3_h, esp01s_h) + wire_z;
|
|
|
|
// Case parameters
|
|
wall = 2.0;
|
|
tol = 0.4;
|
|
outer_w = inner_w + wall*2 + tol*2; // 76.0mm with current board/wiring envelope
|
|
outer_d = inner_d + wall*2 + tol*2; // 38.8mm with current board/wiring envelope
|
|
outer_h = inner_h + wall*2; // 26.0mm with current board/wiring envelope
|
|
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();
|
|
}
|