// RemoteRig camera node case v4 // 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, 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. // - USB-C bottom power inlet and side USB-A passthrough are panel/breakout placeholders; // measure purchased connector flanges/bodies before production prints. $fn = 56; // ----- Main enclosure parameters ----- 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 = 4.0; front_recess_d = 2.0; // lid sits in this front pocket, nominally flush lid_clearance = 0.35; 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 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 screw_head_d = 4.6; boss_d = 6.0; boss_len = 8.0; // Front panel components oled_window_w = 31.0; oled_window_h = 16.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; 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: 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 = 2.4; // clearance behind bridge for strap material strap_bridge_y = strap_gap_y + 2.4; strap_z1 = 23.0; strap_z2 = 50.0; // USB power connector placeholder cutouts usb_c_cutout_w = 10.5; // bottom USB-C female inlet visible opening, X width usb_c_cutout_d = 4.5; // bottom USB-C female inlet visible opening, Y/front-back usb_c_recess_w = 18.0; // shallow underside panel-mount/breakout recess usb_c_recess_d = 10.0; usb_c_y = -7.5; // close to front/service side but clear of screw bosses/lower slots usb_a_cutout_d = 16.0; // side USB-A female opening, Y/front-back dimension usb_a_cutout_h = 8.0; // side USB-A female opening, Z height usb_a_z = 26.0; // mid/lower right side, clear of front lid screws/strap bridges usb_a_y = 2.0; // ----- Utility geometry ----- module rounded_box(size=[10,10,10], r=2, center_xy=true) { // Rounded in XY, straight in Z. linear_extrude(height=size[2]) offset(r=r) 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 yz_rounded_prism(d, x, h, r=2) { // Rounded rectangle in the visible Y/Z plane, extruded through X. // First argument maps to global Y, third argument maps to global Z. rotate([0,90,0]) linear_extrude(height=x, center=true) offset(r=r) square([h-2*r, d-2*r], center=true); } module y_cylinder(d, h, center=true) { rotate([90,0,0]) cylinder(d=d, h=h, center=center); } module screw_boss(x, z) { translate([x, -case_d/2 + front_recess_d + boss_len/2, z]) difference() { y_cylinder(d=boss_d, h=boss_len); y_cylinder(d=screw_d, h=boss_len + 0.8); } } module strap_bridge(zc) { // 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=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); } } // ----- Printable body ----- module camera_node_body_v4() { difference() { union() { difference() { union() { // 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 kept flat/quiet. strap_bridge(strap_z1); strap_bridge(strap_z2); } // 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 strong inset frame. service_depth = front_recess_d + wall + 2.0; translate([0, -case_d/2 + service_depth/2, case_h/2]) 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 USB-C female power inlet: shallow underside recess plus // rounded through-slot for a flush/panel-mount breakout placeholder. translate([0, usb_c_y, -0.35]) rounded_box([usb_c_recess_w, usb_c_recess_d, 0.9], r=1.5); translate([0, usb_c_y, -0.2]) rounded_box([usb_c_cutout_w, usb_c_cutout_d, wall + 1.2], r=1.6); // Right-side USB-A female passthrough power port for the GoPro. translate([case_w/2 - 0.10, usb_a_y, usb_a_z]) yz_rounded_prism(usb_a_cutout_d, wall + 2.8, usb_a_cutout_h, r=0.9); } // 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 + 5.0; screw_z_high = case_h - screw_z_low; screw_boss(-screw_x, screw_z_low); screw_boss( screw_x, screw_z_low); screw_boss(-screw_x, screw_z_high); screw_boss( screw_x, screw_z_high); } // 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 + 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]) y_cylinder(d=screw_d, h=boss_len + front_recess_d + 4.0); } } // ----- Printable front service lid / status panel ----- module camera_node_lid_v4() { panel_through_d = lid_t + lid_lip_t + 2.4; panel_through_y = 0.25; difference() { union() { // 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 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 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, panel_through_y, oled_z]) xz_rounded_prism(oled_window_w, panel_through_d, oled_window_h, r=0.5); // Subtle secondary indicators flanking the rocker, below the OLED bezel. translate([-15.0, panel_through_y, 33.0]) y_cylinder(d=led_hole_d, h=panel_through_d); translate([ 15.0, panel_through_y, 33.0]) y_cylinder(d=led_hole_d, h=panel_through_d); // Small rocker lower on the panel, offset away from the OLED, screws, and slots. translate([0, panel_through_y, 33.0]) xz_rounded_prism(rocker_w, panel_through_d, rocker_h, r=0.8); // Two long rounded horizontal slots near the lower front, matching the reference. translate([0, panel_through_y, 17.0]) xz_rounded_prism(front_slot_w, panel_through_d, front_slot_h, r=front_slot_h/2 - 0.15); translate([0, panel_through_y, 11.0]) xz_rounded_prism(front_slot_w, panel_through_d, front_slot_h, r=front_slot_h/2 - 0.15); // Screw clearance/counterbore holes. screw_x = lid_w/2 - 5.0; 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, panel_through_y, z]) y_cylinder(d=screw_d + 0.4, h=panel_through_d); translate([x, -lid_t/2 + 0.55, z]) y_cylinder(d=screw_head_d, h=1.3); } } } // ----- Non-print preview assembly ----- 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.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/connector volume guides (not printed): ESP modules and USB connector envelopes. 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); color([0.1,0.1,0.1,0.35]) translate([0, usb_c_y, 3.8]) cube([16, 9, 5], center=true); color([0.1,0.1,0.1,0.35]) translate([case_w/2 - 5.5, usb_a_y, usb_a_z]) cube([11, usb_a_cutout_d + 2, usb_a_cutout_h + 2], center=true); } // Non-print review layout: separates the body and front lid while keeping both // front faces oriented toward -Y. Use this STL when checking that the screen, // LED, rocker, USB connector, and lower-slot cutouts are visible in a slicer. module camera_node_front_review_v4() { translate([-34, 0, 0]) rotate([0,0,-18]) color("lightgray") camera_node_body_v4(); translate([34, -case_d/2 + lid_t/2 + 0.03, (case_h - lid_h)/2]) color("gainsboro") camera_node_lid_v4(); } // Select part to render from OpenSCAD CLI with: -D 'part="body"' part = "preview"; // "body", "lid", "preview", or "front_review" if (part == "body") { camera_node_body_v4(); } else if (part == "lid") { camera_node_lid_v4(); } else if (part == "front_review") { camera_node_front_review_v4(); } else { camera_node_preview_v4(); }