// ============================================================
// imx219_mount.scad — IMX219 Camera Radial Arm  Rev A
// Agent: sl-mechanical   2026-02-28
// ============================================================
// Radial arm bracket for 32×32 mm IMX219 camera PCB.
// 4× arms at 0/90/180/270° around the sensor_head platform.
// Camera face tilted 10° nose-down.  CSI ribbon slot along arm.
//
// Print: one arm at a time, flat-side-down — no supports.
//
// RENDER options:
//   "arm"          single arm for slicing (default)
//   "assembly"     all 4 arms positioned around origin
// ============================================================

RENDER = "arm";

// ── Camera PCB (IMX219, 32×32 mm) ────────────────────────────
PCB_SIZE    = 32.0;          // PCB square side
// M2 hole pattern: 24×24 mm square (±12 mm from centre)
M2_SPACING  = 24.0;
M2_D        =  2.4;          // M2 clearance hole

// ── Arm geometry ─────────────────────────────────────────────
// Arm is centred on Y=0, extends in +X direction from origin.
// Base attachment holes near X=0; camera face plate at X=REACH_LEN.

ARM_W       = 26.0;          // arm width (Y direction, centred)
ARM_H       =  5.0;          // arm thickness (Z direction)

// Must match sensor_head.scad ARM_R and ARM_DY_CAM
ARM_R       = 50.0;          // platform attachment radius (used in assembly view)
ARM_DY      =  9.0;          // half-spacing of M4 base attachment holes (Y axis)
ARM_BOLT_X  =  8.0;          // base bolt CL from arm base (X)

REACH_LEN   = 52.0;          // arm extension (X)

FACE_SZ     = PCB_SIZE + 6.0;  // camera face plate side (38 mm)
FACE_THICK  =  4.0;            // face plate thickness (X)

TILT        = 10.0;          // nose-down tilt angle (degrees)

// CSI ribbon slot — runs along bottom face of arm
CSI_W       = 16.0;          // ribbon clearance width
CSI_H       =  2.0;          // slot depth

// ── Fasteners ─────────────────────────────────────────────────
M4_D        =  4.5;          // M4 clearance hole

$fn = 64;
e   = 0.01;

// ─────────────────────────────────────────────────────────────
// imx219_arm()
//   Arm centred on Y=0.  Base at X=0, tip at X=REACH_LEN.
// ─────────────────────────────────────────────────────────────
module imx219_arm() {
    difference() {
        union() {
            // Arm body — centred on Y axis
            translate([0, -ARM_W/2, 0])
                cube([REACH_LEN, ARM_W, ARM_H]);

            // Camera face plate at tip, tilted TILT° nose-down
            translate([REACH_LEN, 0, ARM_H/2])
                rotate([0, TILT, 0])
                    translate([0, -FACE_SZ/2, -FACE_SZ/2])
                        cube([FACE_THICK, FACE_SZ, FACE_SZ]);
        }

        // ── 2× M4 base attachment holes ───────────────────────
        for (s = [-1, 1])
            translate([ARM_BOLT_X, s * ARM_DY, -e])
                cylinder(d = M4_D, h = ARM_H + 2*e);

        // ── CSI ribbon slot — bottom face of arm ──────────────
        translate([REACH_LEN * 0.2, -CSI_W/2, -e])
            cube([REACH_LEN * 0.6, CSI_W, CSI_H + e]);

        // ── 4× M2 camera PCB holes on face plate ─────────────
        translate([REACH_LEN, 0, ARM_H/2])
            rotate([0, TILT, 0])
                for (dy = [-M2_SPACING/2, M2_SPACING/2])
                    for (dz = [-M2_SPACING/2, M2_SPACING/2])
                        translate([-e, dy, dz])
                            rotate([0, 90, 0])
                                cylinder(d = M2_D, h = FACE_THICK + 2*e);
    }
}

// ─────────────────────────────────────────────────────────────
// Render selector
// ─────────────────────────────────────────────────────────────
if (RENDER == "arm") {
    imx219_arm();

} else if (RENDER == "assembly") {
    // 4 arms at 90° intervals, base at ARM_R from stem CL
    for (a = [0, 90, 180, 270])
        rotate([0, 0, a])
            translate([ARM_R, 0, 0])
                color("SkyBlue", 0.9)
                    imx219_arm();
}
