saltylab-firmware/chassis/imx219_mount.scad
sl-mechanical 23f2daa3cd feat: sensor head mounts — stem collar, RPLIDAR, RealSense, 4× IMX219
Part of Phase 2 sensor mount designs for SaltyBot 25 mm mast.

Files added:
  chassis/sensor_head.scad        — split collar (25 mm OD stem) + octagonal platform
  chassis/rplidar_mount.scad      — anti-vibration ring for RPLIDAR A1M8 (Ø58 mm BC)
  chassis/realsense_mount.scad    — RealSense D435i arm bracket, 10° tilt, 1/4-20 nut
  chassis/imx219_mount.scad       — 4× IMX219 radial arms, 10° tilt, CSI ribbon slot
  chassis/sensor_head_assembly.md — assembly diagram + fastener BOM + print settings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 22:53:18 -05:00

105 lines
4.8 KiB
OpenSCAD
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ============================================================
// 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();
}