// ============================================================
// realsense_mount.scad — RealSense D435i Bracket  Rev A
// Agent: sl-mechanical   2026-02-28
// ============================================================
// Single-piece bracket. Bolts to sensor_head platform front
// face via 2× M4 bolts.  Holds D435i at 10° nose-down tilt.
//
// RealSense D435i specs used:
//   Body: 90 × 25 × 25 mm (W × H × D)
//   Mount: 1/4-20 UNC female (bottom centre)
//
// Print orientation: flat base face on build plate — no supports.
//
// RENDER options:
//   "bracket"    print-ready single piece (default)
//   "assembly"   bracket + camera outline
// ============================================================

RENDER = "bracket";

// ── Camera body ──────────────────────────────────────────────
CAM_W       = 90.0;          // camera width
CAM_H       = 25.0;          // camera height
CAM_D       = 25.0;          // camera depth

// ── Bracket geometry ─────────────────────────────────────────
BASE_W      = 40.0;          // base plate width (Y direction)
BASE_D      = 20.0;          // base plate depth (X direction)
BASE_H      =  8.0;          // base plate thickness (Z direction)

ARM_W       = 24.0;          // arm width
ARM_H       =  8.0;          // arm thickness
ARM_LEN     = 75.0;          // arm length (X direction from base edge)

FACE_W      = 30.0;          // camera face plate width
FACE_D      =  8.0;          // face plate thickness (holds camera)
TILT        = 10.0;          // nose-down tilt (degrees)

// ── Fasteners ────────────────────────────────────────────────
M4_D        =  4.5;          // M4 clearance hole
M4_DY       = 18.0;          // half-spacing of base attachment holes
                              // ← must match sensor_head ARM_DY_RS

// 1/4-20 UNC: tap drill ≈ 5.5 mm.
// We print a nut pocket for a 1/4-20 hex nut captured in the face.
NUT1420_AF  = 11.1;          // 1/4-20 hex nut across-flats (7/16")
NUT1420_H   =  5.6;          // 1/4-20 hex nut thickness (7/32")
NUT1420_BORE=  6.5;          // 1/4-20 bolt clearance through face
NUT_POCKET_EXTRA = 0.4;      // print clearance on nut pocket

$fn = 64;
e   = 0.01;

// ─────────────────────────────────────────────────────────────
module realsense_bracket() {
    union() {
        // ── Base plate (attaches to platform top) ────────────
        difference() {
            translate([-BASE_D, -BASE_W/2, 0])
                cube([BASE_D, BASE_W, BASE_H]);

            // 2× M4 holes through base, ±ARM_DY_RS
            for (dy = [-M4_DY, M4_DY])
                translate([-BASE_D/2, dy, -e])
                    cylinder(d = M4_D, h = BASE_H + 2*e);
        }

        // ── Arm extending in +X direction ────────────────────
        difference() {
            hull() {
                translate([0,     -ARM_W/2, 0]) cube([e,     ARM_W, ARM_H]);
                translate([ARM_LEN,-ARM_W/2, 0]) cube([e,    ARM_W, ARM_H]);
            }
            // No internal cuts here — arm is solid for rigidity
        }

        // ── Camera face plate at arm tip, tilted TILT° down ──
        translate([ARM_LEN, 0, ARM_H/2])
            rotate([0, TILT, 0])
                translate([0, 0, -ARM_H/2])
                    difference() {
                        translate([0, -FACE_W/2, 0])
                            cube([FACE_D, FACE_W, CAM_H + 6]);

                        // 1/4-20 hex nut pocket (captured, opens toward +X)
                        translate([FACE_D - NUT1420_H, 0, (CAM_H + 6)/2])
                            rotate([0, 90, 0])
                                cylinder(d = (NUT1420_AF + NUT_POCKET_EXTRA) / cos(30),
                                         h = NUT1420_H + e, $fn = 6);

                        // 1/4-20 bore through full face depth
                        translate([-e, 0, (CAM_H + 6)/2])
                            rotate([0, 90, 0])
                                cylinder(d = NUT1420_BORE, h = FACE_D + 2*e);
                    }
    }
}

// ─────────────────────────────────────────────────────────────
// Render selector
// ─────────────────────────────────────────────────────────────
if (RENDER == "bracket") {
    realsense_bracket();

} else if (RENDER == "assembly") {
    color("LightGray", 0.9)    realsense_bracket();

    // Camera body outline
    translate([ARM_LEN, 0, ARM_H/2])
        rotate([0, TILT, 0])
            translate([FACE_D, -CAM_W/2, -(CAM_H/2 + 3)])
                color("DimGray", 0.6)
                    cube([CAM_D, CAM_W, CAM_H]);
}
