Add camera node case v4 status panel CAD #11

Merged
overseer merged 8 commits from agent/hermes/camera-node-case-v4-status-panel into dev 2026-05-23 11:31:40 -04:00
6 changed files with 97955 additions and 74098 deletions
Showing only changes of commit bbc6b1ea05 - Show all commits
+8 -6
View File
@@ -4,7 +4,7 @@
## Active / Ready for CAD prototype
### Camera node case v4 — status panel + strap mount
### Camera node case v4 — upright status panel + strap mount
**Status:** Parametric OpenSCAD source created; body/lid/preview STLs exported and validated watertight. Ready for CAD review, exact part measurement, and first prototype print.
@@ -20,16 +20,18 @@
**Design direction:**
- Stand-mounted camera node enclosure; the case still does **not** mount to the GoPro.
- Primary mounting is now reusable cloth zip ties / Velcro straps through rear case channels, not a clamp/dovetail.
- Front has a recessed/flush service lid similar to a field-service status panel.
- Stand-mounted upright camera node enclosure; the case still does **not** mount to the GoPro.
- Visual direction now matches the original green appliance-style reference: tall vertical body, large inset front panel, centered OLED near the upper third, blank middle area, two long rounded lower slots, and bottom-center cable exit.
- This replaces the rejected wide/low generic electronics-box layout from the first v4 attempt.
- Primary mounting is reusable cloth zip ties / Velcro straps through low-profile external rear belt-loop channels, not a clamp/dovetail.
- Front has a recessed/flush full-height service lid similar to a field-service status panel.
- Lid includes cutouts for:
- 1.3-inch OLED/status screen.
- separate 3 mm power LED.
- single 3 mm RGB status LED replacing red/green status LEDs.
- small rocker on/off switch.
- lower vent/style slots.
- Body includes screw bosses, recessed lid pocket, lid locating geometry, bottom cable exit/strain-relief notch, and two rear horizontal strap channels to resist rotation on a stand.
- two long rounded lower front slots styled after the reference.
- Body includes screw bosses, recessed lid pocket, lid locating geometry, bottom cable exit/strain-relief notch, and two rear horizontal external belt-loop strap channels to resist rotation on a stand.
- Internal envelope is sized for known module dimensions plus service clearance:
- ESP32-C3 Super Mini: 22.5 × 18 mm.
- ESP-01S: ~24.7 × 14.3 × 12 mm.
+10 -10
View File
@@ -5,7 +5,7 @@
## Overview
Each camera node is two ESP boards in a small stand-mounted case. The case **does not attach to the camera**; it straps to a tripod/lighting stand with reusable cloth zip ties / Velcro straps. Powered by a standard USB power bank.
Each camera node is two ESP boards in a small upright stand-mounted case. The case **does not attach to the camera**; it straps to a tripod/lighting stand with reusable cloth zip ties / Velcro straps. Powered by a standard USB power bank.
```
┌─────────────────┐
@@ -31,7 +31,7 @@ Each camera node is two ESP boards in a small stand-mounted case. The case **doe
|------|-----|------|-------|
| ESP32-C3 Super Mini | 1 | ~$4$6 | MQTT / hub-side bridge; known board envelope 22.5 × 18 mm |
| ESP-01S / ESP8266 module | 1 | ~$2$3 | Camera-side GoPro Wi-Fi bridge; known envelope ~24.7 × 14.3 × 12 mm |
| 1.3-inch OLED/status screen | 1 | ~$4$8 | Prototype CAD assumes ~31 × 16 mm visible window / ~35 × 19 mm panel clearance; confirm exact module |
| 1.3-inch OLED/status screen | 1 | ~$4$8 | Prototype CAD assumes ~31 × 16 mm visible window / ~37 × 22 mm panel recess; confirm exact module |
| 3 mm power LED | 1 | <$1 | Separate always-power/5V indicator |
| 3 mm RGB status LED | 1 | <$1 | Replaces separate red/green status LEDs; firmware can map node states to color |
| Small rocker switch | 1 | ~$1$3 | On/off switch; prototype CAD assumes 13 × 19 mm snap-in opening |
@@ -48,17 +48,17 @@ Each camera node is two ESP boards in a small stand-mounted case. The case **doe
**Current source:** `hardware/case/camera-node-case-v4.scad`
**Pipeline:** `hardware/DESIGN_PIPELINE.md`
The v4 case replaces the v3 clamp/dovetail concept with a simpler strap-mounted field enclosure:
The current v4 CAD replaces the rejected wide/low electronics-box layout with a tall appliance-style enclosure matching the original upright reference: a clean vertical body, large inset front panel, OLED near the top, open blank middle area, two long rounded lower slots, and a bottom-center cable exit. It also replaces the v3 clamp/dovetail concept with a simpler strap-mounted field enclosure:
1. **Case body** — shell sized around ESP32-C3 Super Mini + ESP-01S with service/wiring clearance.
2. **Flush/recessed front service lid** — screw-on front status panel with locating lip.
2. **Flush/recessed full-height front service lid** — screw-on front panel with locating lip and a restrained raised/recessed border.
3. **Front panel controls/indicators**:
- 1.3-inch OLED/status screen window.
- 3 mm **PWR** LED.
- single 3 mm **RGB STAT** LED for state-dependent colors.
- small rectangular rocker switch cutout.
- lower vent/style slots.
4. **Rear strap channels** — two raised horizontal cloth zip-tie / Velcro strap paths to reduce rotation on a tripod/stand.
- two long rounded lower front slots styled after the reference appliance face.
4. **Rear strap channels** — two low-profile external belt-loop cloth zip-tie / Velcro strap paths to reduce rotation on a tripod/stand without visually dominating the body.
5. **Bottom cable exit** — cable/strain-relief notch for USB/power wiring.
### Export wrappers
@@ -167,12 +167,12 @@ Prototype v4 nominal CAD dimensions:
| Part / feature | W × D × H (mm) |
|---|---|
| Case shell external | ~68 × 42 × 32 |
| Case with rear strap bridges | ~68 × 45.2 × 32 |
| Front recessed lid | visible panel ~60 × 2 × 26; total with locating lip ~60 × 3 × 26 |
| Case shell external | ~56 × 36 × 82 |
| Case with rear strap bridges | ~56 × 40 × 82 |
| Front recessed lid | visible panel ~48 × 2 × 74; total with locating lip ~48 × 3 × 74 |
| OLED visible window assumption | ~31 × 16 |
| Rocker cutout assumption | ~13 × 19 |
| Rear strap channels | two horizontal pass-through paths, ~48 mm usable slot width, ~4.2 mm strap-thickness clearance |
| Rear strap channels | two low-profile external belt-loop paths, ~33 mm usable slot width, ~4.2 mm strap-thickness clearance |
| Board clearance targets | ESP32-C3 22.5 × 18 mm + ESP-01S 24.7 × 14.3 × 12 mm plus wiring/service clearance |
These dimensions are placeholders for the first CAD prototype. Measure the actual OLED module, rocker switch, LEDs, screws, USB cable bend radius, and strap width/thickness before committing to production prints.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+96 -97
View File
@@ -1,33 +1,34 @@
// RemoteRig camera node case v4
// Parametric OpenSCAD prototype for a status-panel camera node enclosure.
// Upright appliance-style OpenSCAD prototype for a strap-mounted camera node.
// Units: millimeters. Coordinate system: X=width, Y=depth/front-back, Z=height.
// Front/service lid is on the -Y face. Rear strap channels are on the +Y face.
//
// v4 visual direction: tall/upright appliance/control box matching the original
// reference image, replacing the rejected wide, low generic electronics box.
// Nominal body: 56 W x 36 D x 82 H mm; with low rear strap bridges ~40 D.
//
// Prototype assumptions to confirm against purchased parts:
// - 1.3 inch OLED module/window opening: 31 x 16 mm visible window, 35 x 19 mm panel clearance.
// - 1.3 inch OLED module/window opening: 31 x 16 mm visible window, 37 x 22 mm panel recess.
// - Small rocker switch cutout: 13 x 19 mm rectangular snap-in opening.
// - LEDs: two 3 mm panel LEDs (PWR + RGB STAT) with 3.2 mm holes.
// - Boards: ESP32-C3 Super Mini 22.5 x 18 mm, ESP-01S 24.7 x 14.3 x 12 mm.
$fn = 48;
$fn = 56;
// ----- Main enclosure parameters -----
case_w = 68; // external width; room for OLED + LEDs + switch
case_d = 42; // external depth; board stack + wiring clearance
case_h = 32; // external height
case_w = 56; // upright appliance-style external width
case_d = 36; // depth for module stack + wiring clearance
case_h = 82; // tall vertical appliance-style height
wall = 2.2;
corner_r = 3.0;
corner_r = 4.0;
front_recess_d = 2.0; // lid sits in this front pocket, nominally flush
lid_clearance = 0.35;
lid_w = case_w - 8;
lid_h = case_h - 6;
lid_w = case_w - 8; // nearly full-height/front-width inset panel
lid_h = case_h - 8;
lid_t = 2.0;
lid_lip_t = 1.2; // locating lip protrudes inside service opening
lid_lip_inset = 2.1;
// Central body opening avoids the four corner screw bosses. Separate local
// clearances below handle the OLED/switch bodies without cutting away bosses.
service_opening_w = 46.0;
service_opening_h = 11.5;
service_opening_w = lid_w - 10.0;
service_opening_h = lid_h - 16.0;
// Hardware
screw_d = 2.4; // M2 self-tapping / pilot; confirm hardware
@@ -36,29 +37,29 @@ boss_d = 6.0;
boss_len = 8.0;
// Front panel components
// OLED values are intentionally conservative prototype placeholders.
oled_window_w = 31.0;
oled_window_h = 16.0;
oled_bezel_w = 35.0; // engraved/recessed visual outline around window
oled_bezel_h = 19.0;
oled_bezel_w = 37.0; // shallow recessed visual outline around window
oled_bezel_h = 22.0;
oled_z = 53.0; // upper third, clear of top screw counterbores
led_hole_d = 3.2; // 3 mm LED clearance
rocker_w = 13.0; // prototype cutout; measure purchased rocker
rocker_h = 19.0;
vent_slot_w = 7.0;
vent_slot_h = 1.7;
front_slot_w = 34.0; // two long rounded horizontal slots near lower front
front_slot_h = 3.2;
// Rear reusable cloth zip-tie / Velcro strap channels
strap_bridge_w = case_w - 12;
strap_bridge_h = 7.5; // outer raised tab height
// Rear reusable cloth zip-tie / Velcro strap channels: low-profile external loops.
strap_bridge_w = case_w - 14;
strap_bridge_h = 6.5; // outer raised rail height
strap_slot_h = 4.2; // strap thickness opening; adjust for cloth ties
strap_gap_y = 3.2; // clearance behind bridge for strap material
strap_bridge_y = strap_gap_y + 2.2;
strap_z1 = 8.5;
strap_z2 = 23.5;
strap_gap_y = 2.4; // clearance behind bridge for strap material
strap_bridge_y = strap_gap_y + 2.4;
strap_z1 = 23.0;
strap_z2 = 50.0;
// Cable exit
cable_notch_w = 13.0;
cable_notch_h = 6.0;
cable_notch_h = 6.5;
// ----- Utility geometry -----
module rounded_box(size=[10,10,10], r=2, center_xy=true) {
@@ -68,6 +69,14 @@ module rounded_box(size=[10,10,10], r=2, center_xy=true) {
square([size[0]-2*r, size[1]-2*r], center=center_xy);
}
module xz_rounded_prism(w, d, h, r=2) {
// Rounded rectangle in the visible X/Z plane, extruded through Y.
rotate([-90,0,0])
linear_extrude(height=d, center=true)
offset(r=r)
square([w-2*r, h-2*r], center=true);
}
module y_cylinder(d, h, center=true) {
rotate([90,0,0]) cylinder(d=d, h=h, center=center);
}
@@ -81,17 +90,23 @@ module screw_boss(x, z) {
}
module strap_bridge(zc) {
// Raised rear bridge with a smooth-ish strap tunnel through it.
// It intentionally overlaps the main shell by ~2.2 mm so the STL is a
// single printable body, not separate coincident strap-tab volumes.
translate([0, case_d/2 + strap_bridge_y/2 - 2.2, zc - strap_bridge_h/2])
// Low external rear belt-loop bridge for cloth ties/Velcro.
// The slot is entirely behind the rear wall so it does not expose the
// electronics cavity; a small overlap keeps the bridge connected to shell.
bridge_overlap_y = 0.8;
translate([0, case_d/2 + strap_bridge_y/2 - bridge_overlap_y, zc - strap_bridge_h/2])
union() {
difference() {
rounded_box([strap_bridge_w, strap_bridge_y, strap_bridge_h], r=2.0);
// Through-slot for the cloth tie. It cuts all the way through Y,
// while leaving side posts that tie the upper/lower rails together.
// Matching rear-wall cutouts are made in camera_node_body_v4().
translate([0, 0, (strap_bridge_h - strap_slot_h)/2])
rounded_box([strap_bridge_w - 8.0, strap_bridge_y + 0.8, strap_slot_h], r=1.2);
rounded_box([strap_bridge_w, strap_bridge_y, strap_bridge_h], r=1.8);
translate([0, -strap_bridge_y/2 + bridge_overlap_y + 0.05 + (strap_bridge_y + 1.0)/2,
(strap_bridge_h - strap_slot_h)/2])
rounded_box([strap_bridge_w - 9.0, strap_bridge_y + 1.0, strap_slot_h], r=1.1);
}
// Rear-wall weld pad: mechanically joins the external bridge to the
// shell while keeping the belt slot outside the electronics cavity.
translate([0, -strap_bridge_y/2 + bridge_overlap_y, strap_bridge_h/2])
cube([strap_bridge_w, 0.9, strap_bridge_h], center=true);
}
}
@@ -101,52 +116,37 @@ module camera_node_body_v4() {
union() {
difference() {
union() {
// Outer shell.
translate([0,0,0]) rounded_box([case_w, case_d, case_h], r=corner_r);
// Upright outer shell with softened appliance-like corners.
rounded_box([case_w, case_d, case_h], r=corner_r);
// Rear cloth zip-tie / Velcro strap bridges.
// Rear cloth zip-tie / Velcro strap bridges kept flat/quiet.
strap_bridge(strap_z1);
strap_bridge(strap_z2);
}
// Front recessed lid pocket (shallow, so the lid can sit flush).
translate([0, -case_d/2 - 0.2, case_h/2])
cube([lid_w + lid_clearance, front_recess_d + 0.3, lid_h + lid_clearance], center=true);
// Full-height front recessed lid pocket, like the green reference panel.
translate([0, -case_d/2 + front_recess_d/2, case_h/2])
cube([lid_w + lid_clearance, front_recess_d + 0.4, lid_h + lid_clearance], center=true);
// Through service opening behind the lid, leaving a recessed ledge/frame.
// Through service opening behind the lid, leaving a strong inset frame.
service_depth = front_recess_d + wall + 2.0;
translate([0, -case_d/2 + service_depth/2, case_h/2])
cube([service_opening_w, service_depth + 0.4, service_opening_h], center=true);
// Local front clearances for the OLED module and rocker-switch body.
// These keep the screw-boss corner material intact while still leaving
// room for front-panel components and wiring to enter the body cavity.
translate([0, -case_d/2 + service_depth/2, (case_h - lid_h)/2 + lid_h - 9.5])
cube([oled_bezel_w + 2.0, service_depth + 0.4, oled_bezel_h + 3.0], center=true);
translate([15.5, -case_d/2 + service_depth/2, (case_h - lid_h)/2 + 12.0])
cube([rocker_w + 3.0, service_depth + 0.4, rocker_h + 3.0], center=true);
// Rear-wall pass-through slots for reusable cloth zip-ties / Velcro.
// The slots align with the raised bridges, so straps can thread through
// the back of the case instead of sitting in a closed decorative groove.
for (zc=[strap_z1, strap_z2])
translate([0, case_d/2 + 1.0, zc])
cube([strap_bridge_w - 8.0, 8.0, strap_slot_h], center=true);
xz_rounded_prism(service_opening_w, service_depth + 0.4, service_opening_h, r=2.0);
// Interior electronics cavity: ESP32-C3 Super Mini + ESP-01S plus wiring/service clearance.
cavity_d = case_d - front_recess_d - 2*wall;
translate([0, -case_d/2 + front_recess_d + wall + cavity_d/2, case_h/2])
cube([case_w - 2*wall, cavity_d, case_h - 2*wall], center=true);
// Bottom cable exit / strain-relief notch on lower front edge.
// Bottom center cable exit / strain-relief notch.
translate([0, -case_d/2 + 2.0, -0.05])
cube([cable_notch_w, 9.0, cable_notch_h], center=true);
xz_rounded_prism(cable_notch_w, 9.0, cable_notch_h, r=1.8);
}
// Four protected screw bosses are added after shell hollowing so the
// electronics cavity cannot cut away the receiving material.
screw_x = lid_w/2 - 5.0;
screw_z_low = (case_h - lid_h)/2 + 4.2;
screw_z_low = (case_h - lid_h)/2 + 5.0;
screw_z_high = case_h - screw_z_low;
screw_boss(-screw_x, screw_z_low);
screw_boss( screw_x, screw_z_low);
@@ -154,11 +154,9 @@ module camera_node_body_v4() {
screw_boss( screw_x, screw_z_high);
}
// Final body-level pilot holes cut through the front frame into the
// protected bosses. Without this pass the boss pilot holes can be
// hidden behind solid frame material.
// Final body-level pilot holes cut through the front frame into the protected bosses.
screw_x = lid_w/2 - 5.0;
screw_z_low = (case_h - lid_h)/2 + 4.2;
screw_z_low = (case_h - lid_h)/2 + 5.0;
screw_z_high = case_h - screw_z_low;
for (x=[-screw_x, screw_x], z=[screw_z_low, screw_z_high])
translate([x, -case_d/2 + front_recess_d + boss_len/2, z])
@@ -170,45 +168,41 @@ module camera_node_body_v4() {
module camera_node_lid_v4() {
difference() {
union() {
// Visible flush panel.
translate([0,0,0]) rounded_box([lid_w, lid_t, lid_h], r=0.65);
// Visible full-height flush panel; restrained and not a busy slab.
rounded_box([lid_w, lid_t, lid_h], r=0.65);
// Rear locating lip fits inside the central service opening and helps
// panel alignment. Center it on the body's central opening so it
// does not collide with lower vent geometry.
lip_h = service_opening_h - 0.5;
translate([0, lid_t/2 + lid_lip_t/2 - 0.2, (lid_h - lip_h)/2])
rounded_box([service_opening_w - 0.5, lid_lip_t, lip_h], r=0.45);
// Shallow raised text pads/labels are omitted for print simplicity; add decals or paint-fill.
// Rear locating lip fits inside the large service opening.
translate([0, lid_t/2 + lid_lip_t/2 - 0.2, lid_h/2])
xz_rounded_prism(service_opening_w - 0.8, lid_lip_t, service_opening_h - 0.8, r=1.5);
}
// OLED window and shallow module outline/recess.
translate([0, -0.2, lid_h - 9.5])
cube([oled_window_w, lid_t + lid_lip_t + 0.8, oled_window_h], center=true);
translate([0, -0.35, lid_h - 9.5])
cube([oled_bezel_w, 0.7, oled_bezel_h], center=true);
// OLED window and shallow black-bezel-style recess near the top.
translate([0, -lid_t/2 + 0.35, oled_z])
xz_rounded_prism(oled_bezel_w, 0.9, oled_bezel_h, r=1.3);
translate([0, -0.2, oled_z])
xz_rounded_prism(oled_window_w, lid_t + lid_lip_t + 0.9, oled_window_h, r=0.5);
// LED holes: separate power LED and single RGB status LED.
translate([-17.0, -0.2, 11.5]) y_cylinder(d=led_hole_d, h=lid_t + lid_lip_t + 1.0);
translate([-9.0, -0.2, 11.5]) y_cylinder(d=led_hole_d, h=lid_t + lid_lip_t + 1.0);
// Subtle secondary indicators flanking the rocker, below the OLED bezel.
translate([-15.0, -0.2, 33.0]) y_cylinder(d=led_hole_d, h=lid_t + lid_lip_t + 1.0);
translate([ 15.0, -0.2, 33.0]) y_cylinder(d=led_hole_d, h=lid_t + lid_lip_t + 1.0);
// Rocker switch snap-in opening.
translate([15.5, -0.2, 12.0])
cube([rocker_w, lid_t + lid_lip_t + 1.0, rocker_h], center=true);
// Small rocker lower on the panel, offset away from the OLED, screws, and slots.
translate([0, -0.2, 33.0])
xz_rounded_prism(rocker_w, lid_t + lid_lip_t + 1.0, rocker_h, r=0.8);
// Lower vent / style slots.
for (i=[-2:2])
translate([i*9.5, -0.2, 4.8])
cube([vent_slot_w, lid_t + lid_lip_t + 1.0, vent_slot_h], center=true);
// Two long rounded horizontal slots near the lower front, matching the reference.
translate([0, -0.2, 17.0])
xz_rounded_prism(front_slot_w, lid_t + lid_lip_t + 1.0, front_slot_h, r=front_slot_h/2);
translate([0, -0.2, 11.0])
xz_rounded_prism(front_slot_w, lid_t + lid_lip_t + 1.0, front_slot_h, r=front_slot_h/2);
// Screw clearance/counterbore holes.
screw_x = lid_w/2 - 5.0;
screw_z_low = 4.2;
screw_z_low = 5.0;
screw_z_high = lid_h - screw_z_low;
for (x=[-screw_x, screw_x], z=[screw_z_low, screw_z_high]) {
translate([x, -0.2, z]) y_cylinder(d=screw_d + 0.4, h=lid_t + lid_lip_t + 1.0);
translate([x, -0.15, z]) y_cylinder(d=screw_head_d, h=1.2);
translate([x, -lid_t/2 + 0.55, z]) y_cylinder(d=screw_head_d, h=1.3);
}
}
}
@@ -217,12 +211,17 @@ module camera_node_lid_v4() {
module camera_node_preview_v4(show_lid=true) {
color("lightgray") camera_node_body_v4();
if (show_lid)
translate([0, -case_d/2 - lid_t/2 - 0.2, (case_h - lid_h)/2])
translate([0, -case_d/2 + lid_t/2 + 0.03, (case_h - lid_h)/2])
color("gainsboro") camera_node_lid_v4();
// Dark OLED bezel/window cue for visual review only (not part of exported lid STL when rendering lid).
if (show_lid)
translate([0, -case_d/2 - 0.08, (case_h - lid_h)/2 + oled_z])
color("black") xz_rounded_prism(oled_bezel_w, 0.6, oled_bezel_h, r=1.3);
// Internal board volume guides (not printed): ESP32-C3 and ESP-01S envelopes.
color([0,0.45,0,0.35]) translate([-13, -1, 9]) cube([22.5, 18, 4], center=true);
color([0,0.2,0.8,0.35]) translate([13, -1, 20]) cube([24.7, 14.3, 12], center=true);
color([0,0.45,0,0.35]) translate([-9, -1, 26]) cube([22.5, 18, 4], center=true);
color([0,0.2,0.8,0.35]) translate([9, -1, 45]) cube([24.7, 14.3, 12], center=true);
}
// Select part to render from OpenSCAD CLI with: -D 'part="body"'