From 23f2daa3cde70eb47750d8cd08fcfcbcbeb3272d Mon Sep 17 00:00:00 2001 From: sl-mechanical Date: Sat, 28 Feb 2026 22:53:18 -0500 Subject: [PATCH] =?UTF-8?q?feat:=20sensor=20head=20mounts=20=E2=80=94=20st?= =?UTF-8?q?em=20collar,=20RPLIDAR,=20RealSense,=204=C3=97=20IMX219?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- chassis/imx219_mount.scad | 104 +++++++++++++++++++++ chassis/realsense_mount.scad | 114 ++++++++++++++++++++++ chassis/rplidar_mount.scad | 76 +++++++++++++++ chassis/sensor_head.scad | 161 ++++++++++++++++++++++++++++++++ chassis/sensor_head_assembly.md | 157 +++++++++++++++++++++++++++++++ 5 files changed, 612 insertions(+) create mode 100644 chassis/imx219_mount.scad create mode 100644 chassis/realsense_mount.scad create mode 100644 chassis/rplidar_mount.scad create mode 100644 chassis/sensor_head.scad create mode 100644 chassis/sensor_head_assembly.md diff --git a/chassis/imx219_mount.scad b/chassis/imx219_mount.scad new file mode 100644 index 0000000..080c2bd --- /dev/null +++ b/chassis/imx219_mount.scad @@ -0,0 +1,104 @@ +// ============================================================ +// 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(); +} diff --git a/chassis/realsense_mount.scad b/chassis/realsense_mount.scad new file mode 100644 index 0000000..2f55654 --- /dev/null +++ b/chassis/realsense_mount.scad @@ -0,0 +1,114 @@ +// ============================================================ +// 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]); +} diff --git a/chassis/rplidar_mount.scad b/chassis/rplidar_mount.scad new file mode 100644 index 0000000..f287a38 --- /dev/null +++ b/chassis/rplidar_mount.scad @@ -0,0 +1,76 @@ +// ============================================================ +// rplidar_mount.scad — RPLIDAR A1M8 Anti-Vibration Ring Rev A +// Agent: sl-mechanical 2026-02-28 +// ============================================================ +// Flat ring sits between platform and RPLIDAR A1M8. +// Anti-vibration isolation via 4× M3 silicone grommets +// (same type as FC vibration mounts — Ø6 mm silicone, M3). +// +// Bolt stack (bottom → top): +// M3×30 SHCS → platform (8 mm) → grommet (8 mm) → +// ring (4 mm) → RPLIDAR bottom (threaded M3, ~6 mm engagement) +// +// RENDER options: +// "ring" print-ready flat ring (default) +// "assembly" ring in position on platform stub +// ============================================================ + +RENDER = "ring"; + +// ── RPLIDAR A1M8 ───────────────────────────────────────────── +RPL_BODY_D = 70.0; // body diameter +RPL_BC = 58.0; // M3 mounting bolt circle + +// ── Mount ring ─────────────────────────────────────────────── +RING_OD = 82.0; // outer diameter (RPL_BODY_D + 12 mm) +RING_ID = 30.0; // inner cutout (cable / airflow) +RING_H = 4.0; // ring thickness + +BOLT_D = 3.3; // M3 clearance through-hole +GROMMET_D = 7.0; // silicone grommet OD (seat recess on bottom) +GROMMET_H = 1.0; // seating recess depth + +$fn = 64; +e = 0.01; + +// ───────────────────────────────────────────────────────────── +module rplidar_ring() { + difference() { + cylinder(d = RING_OD, h = RING_H); + + // Central cutout + translate([0, 0, -e]) + cylinder(d = RING_ID, h = RING_H + 2*e); + + // 4× M3 clearance holes on bolt circle + for (a = [45, 135, 225, 315]) { + translate([RPL_BC/2 * cos(a), RPL_BC/2 * sin(a), -e]) + cylinder(d = BOLT_D, h = RING_H + 2*e); + } + + // Grommet seating recesses — bottom face + for (a = [45, 135, 225, 315]) { + translate([RPL_BC/2 * cos(a), RPL_BC/2 * sin(a), -e]) + cylinder(d = GROMMET_D, h = GROMMET_H + e); + } + } +} + +// ───────────────────────────────────────────────────────────── +// Render selector +// ───────────────────────────────────────────────────────────── +if (RENDER == "ring") { + rplidar_ring(); + +} else if (RENDER == "assembly") { + // Platform stub + color("Silver", 0.5) + difference() { + cylinder(d = 90, h = 8); + translate([0, 0, -e]) cylinder(d = 25.4, h = 8 + 2*e); + } + // Ring floating 8 mm above (grommet gap) + color("SkyBlue", 0.9) + translate([0, 0, 8 + 8]) + rplidar_ring(); +} diff --git a/chassis/sensor_head.scad b/chassis/sensor_head.scad new file mode 100644 index 0000000..2d4a62e --- /dev/null +++ b/chassis/sensor_head.scad @@ -0,0 +1,161 @@ +// ============================================================ +// sensor_head.scad — Sensor Head Platform Rev A 2026-02-28 +// Agent: sl-mechanical +// ============================================================ +// Clamps to 25 mm OD vertical stem (top of mast). +// Platform hosts: +// • RPLIDAR A1M8 — centred, topmost +// • RealSense D435i — front arm, 10° down tilt +// • 4× IMX219 cameras — radial arms, 90° apart, 10° down +// +// RENDER options: +// "assembly" 3-D exploded-ish view (default) +// "collar_front" front collar half for slicing (print 2) +// "collar_rear" rear collar half for slicing +// "platform_2d" flat projection → DXF +// ============================================================ + +RENDER = "assembly"; + +// ── Stem ───────────────────────────────────────────────────── +STEM_OD = 25.0; // actual stem OD (mm) +STEM_BORE = 25.4; // collar bore (+ 0.4 mm clearance for FDM) + +// ── Collar ─────────────────────────────────────────────────── +COL_OD = 52.0; // outer diameter +COL_H = 36.0; // height +COL_BOLT_X = 19.0; // M4 clamping bolt CL from stem axis +COL_BOLT_D = 4.5; // M4 clearance hole +COL_NUT_W = 7.0; // M4 hex nut A/F +COL_NUT_H = 3.4; // M4 hex nut thickness + +// ── Platform ───────────────────────────────────────────────── +PLAT_OD = 120.0; // octagonal platform, across-flats ≈ OD +PLAT_H = 8.0; // plate thickness +PLAT_Z = COL_H; // platform bottom sits atop collar + +// ── RPLIDAR bolt circle ─────────────────────────────────────── +RPL_BC = 58.0; // M3 hole bolt circle diameter +RPL_HOLE_D = 3.3; // M3 clearance +RPL_RECESS_D = 72.0; // alignment lip diameter (body + 2 mm clearance) +RPL_RECESS_H = 1.5; // recess depth + +// ── Sensor arm attachment holes ─────────────────────────────── +// RealSense arm: 2× M4 holes at X = +ARM_R, Y = ±ARM_DY_RS +ARM_R = 50.0; // radial distance from stem CL +ARM_DY_RS = 18.0; // half-spacing for RealSense pair +// IMX219 arms: 4 × 2 M4 holes at each 90° cardinal, tangential offset ±ARM_DY_CAM +ARM_DY_CAM = 9.0; // half-spacing for IMX219 pair + +ARM_HOLE_D = 4.5; // M4 clearance + +$fn = 64; +e = 0.01; + +// ───────────────────────────────────────────────────────────── +// collar_half(side) +// side = "front" (+Y) | "rear" (-Y) +// Print flat-face-down (mating face on build plate). +// ───────────────────────────────────────────────────────────── +module collar_half(side = "front") { + difference() { + // ── Body: D-shaped half-cylinder ───────────────────── + intersection() { + cylinder(d = COL_OD, h = COL_H); + translate([-COL_OD/2, (side == "front") ? 0 : -COL_OD/2, 0]) + cube([COL_OD, COL_OD/2, COL_H]); + } + + // ── Stem bore ──────────────────────────────────────── + translate([0, 0, -e]) + cylinder(d = STEM_BORE, h = COL_H + 2*e); + + // ── M4 clamping bolt clearance holes (Y direction) ─── + for (bx = [-COL_BOLT_X, COL_BOLT_X]) { + translate([bx, (side == "front") ? COL_OD/2 : 0, COL_H/2]) + rotate([90, 0, 0]) + cylinder(d = COL_BOLT_D, h = COL_OD/2 + e); + } + + // ── M4 hex nut pockets (rear half only) ────────────── + if (side == "rear") { + for (bx = [-COL_BOLT_X, COL_BOLT_X]) { + translate([bx, -(COL_OD/4 + e), COL_H/2]) + rotate([90, 0, 0]) + cylinder(d = COL_NUT_W / cos(30), h = COL_NUT_H + e, $fn = 6); + } + } + + // ── M4 set screw — height / rotation lock (front half) ─ + if (side == "front") { + translate([0, COL_OD/2, COL_H * 0.72]) + rotate([90, 0, 0]) + cylinder(d = COL_BOLT_D, h = COL_OD/2 - STEM_BORE/2 + e); + } + } +} + +// ───────────────────────────────────────────────────────────── +// platform() +// ───────────────────────────────────────────────────────────── +module platform() { + difference() { + // ── Octagonal disc ─────────────────────────────────── + cylinder(d = PLAT_OD, h = PLAT_H, $fn = 8); + + // ── Stem passage ───────────────────────────────────── + translate([0, 0, -e]) + cylinder(d = STEM_BORE, h = PLAT_H + 2*e); + + // ── RPLIDAR alignment recess (top face) ────────────── + translate([0, 0, PLAT_H - RPL_RECESS_H]) + cylinder(d = RPL_RECESS_D, h = RPL_RECESS_H + e); + + // ── RPLIDAR M3 bolt holes — 58 mm BC ───────────────── + for (a = [45, 135, 225, 315]) + translate([RPL_BC/2 * cos(a), RPL_BC/2 * sin(a), -e]) + cylinder(d = RPL_HOLE_D, h = PLAT_H + 2*e); + + // ── RealSense arm M4 holes — front (+X), ±ARM_DY_RS ── + for (dy = [-ARM_DY_RS, ARM_DY_RS]) + translate([ARM_R, dy, -e]) + cylinder(d = ARM_HOLE_D, h = PLAT_H + 2*e); + + // ── IMX219 arm M4 holes — 4 × cardinal, ±ARM_DY_CAM ─ + // Tangential perpendicular for angle a: (sin(a), -cos(a)) + for (a = [0, 90, 180, 270]) + for (s = [-1, 1]) + translate([ + ARM_R * cos(a) + s * ARM_DY_CAM * sin(a), + ARM_R * sin(a) - s * ARM_DY_CAM * cos(a), + -e + ]) + cylinder(d = ARM_HOLE_D, h = PLAT_H + 2*e); + + // ── Lightening pockets — between arm attachment holes ─ + for (a = [45, 135, 225, 315]) + translate([(PLAT_OD/2 - 22) * cos(a), + (PLAT_OD/2 - 22) * sin(a), -e]) + cylinder(d = 20, h = PLAT_H + 2*e); + } +} + +// ───────────────────────────────────────────────────────────── +// Render selector +// ───────────────────────────────────────────────────────────── +if (RENDER == "assembly") { + color("SkyBlue", 0.9) collar_half("front"); + color("DodgerBlue", 0.9) mirror([0, 1, 0]) collar_half("rear"); + color("Silver", 0.85) translate([0, 0, PLAT_Z]) platform(); + +} else if (RENDER == "collar_front") { + collar_half("front"); + +} else if (RENDER == "collar_rear") { + collar_half("rear"); + +} else if (RENDER == "platform_2d") { + projection(cut = true) + translate([0, 0, -(PLAT_Z + PLAT_H / 2)]) + platform(); +} diff --git a/chassis/sensor_head_assembly.md b/chassis/sensor_head_assembly.md new file mode 100644 index 0000000..3df9434 --- /dev/null +++ b/chassis/sensor_head_assembly.md @@ -0,0 +1,157 @@ +# SaltyBot Sensor Head — Assembly Diagram +**Rev A — 2026-02-28 — sl-mechanical** + +--- + +## Overview + +The sensor head mounts on top of the 25 mm OD vertical stem. +Five printed/machined parts stack on a split collar platform. + +--- + +## TOP VIEW (schematic) + +``` + FRONT (+X) + ↑ + [IMX219 arm] | [IMX219 arm] + 90° | 0° + ↑ +---------+ ↑ + | | | | + [IMX219]←----[•]---| RPLIDAR |---[•]----→[IMX219] + 270° | | Ø70mm | | 90° + ↓ | | ↓ + +---------+ + | PLAT | + | Ø120mm | + | (octag) | + +---------+ + ↑ | | ↑ + [RS arm]---[•]---| COLLAR |---[•] + | Ø52mm | + +---------+ + | + 25mm stem + ↓ +``` + +--- + +## SIDE VIEW (section through front, to scale) + +``` + Z + ↑ + │ + │ RPLIDAR A1M8 (Ø70 × 30 mm) + │ ┌────────────────────┐ ← Z ≈ 52 mm (top of RPLIDAR) + │ │ ██████████████ │ + │ │ ██ A1M8 ██ │ ← Z ≈ 22 mm (bottom of RPLIDAR) + │ └────────────────────┘ + │ │ │ │ │ ← M3×30 bolts (4 off) + │ ┌────┴────┴────┴────┐ + │ │ rplidar_ring.scad│ ← Z = 14..18 mm (4 mm ring) + │ │ [silicone gromm]│ ← grommets 8 mm below ring + │ └───────────────────┘ + │ ┌───────────────────┐ + │ │ P L A T F O R M │ ← Z = 36..44 mm + │ │ (octag, Ø120mm) │ + │ └───────────────────┘ + │ │ COLLAR │ + │ ┌────┴────────┴────┐ + │ │ COLLAR FRONT │ ← Z = 0..36 mm + │ │ │ stem bore │ │ + │ │ COLLAR REAR │ + │ └──────────────────┘ + │ │ + │ 25 mm STEM + └─────────────────────────────────────── X +``` + +> **Note on Z references:** Z=0 is the bottom of the collar. +> Stem clamp bolts lock the sensor head at chosen height on the mast. + +--- + +## IMX219 Arm (side view — one arm shown) + +``` + Platform edge Camera PCB + │ │ + ─────┤══════════════════════════════════════╗ + │ ←── 52 mm arm ──────────────────► ║ IMX219 + ─────┤══════════════════════════════════════╝ ← 10° nose down + │ 2× M4 4× M2 + │ base bolts PCB bolts + │ [slot: CSI ribbon through arm length] +``` + +--- + +## RealSense Arm (side view) + +``` + Platform edge + │ 2× M4 + ─────┤ + │ Base ←── 75 mm arm ──────────────────► + ─────┤ plate + │ (flat) ══════════════════════════════════╗ + ║ ← 10° nose down + ║ D435i + ║ 90×25×25 + 1/4-20 nut (captured) +``` + +--- + +## Assembly Sequence + +| Step | Action | +|------|--------| +| 1 | Print 2× `collar_half` (flat-face-down; mirror one in slicer) | +| 2 | Print 1× `platform` | +| 3 | Print 1× `rplidar_ring` | +| 4 | Print 1× `realsense_bracket` | +| 5 | Print 4× `imx219_arm` (one per direction) | +| 6 | Seat 4× M3 silicone anti-vibration grommets in platform holes | +| 7 | Place rplidar_ring on grommets; pass 4× M3×30 SHCS from platform bottom up through ring | +| 8 | Set RPLIDAR A1M8 on ring; tighten M3×30 into RPLIDAR tapped holes (fingertight) | +| 9 | Thread 1/4-20 hex nut into realsense_bracket pocket; bolt D435i onto bracket | +| 10 | Bolt realsense_bracket to platform front with 2× M4×16 SHCS | +| 11 | Bolt 4× imx219_arm to platform with 2× M4×16 SHCS each | +| 12 | Snap IMX219 PCBs onto arm face plates with 4× M2×6 BHCS each | +| 13 | Route CSI ribbon cables through arm slots toward platform centre | +| 14 | Assemble collar halves around stem (flat faces mating); tighten M4×30 clamping bolts | +| 15 | Tighten M4 set screw in front collar half to lock height | +| 16 | Torque RPLIDAR M3 bolts: 0.5 N·m | + +--- + +## Fastener Summary + +| Qty | Size | Use | +|-----|------|-----| +| 2 | M4×30 SHCS | Collar clamping bolts | +| 1 | M4×10 set screw | Collar height / rotation lock | +| 2 | M4×16 SHCS | RealSense bracket to platform | +| 8 | M4×16 SHCS | IMX219 arms to platform (2 per arm) | +| 4 | M2×6 BHCS | IMX219 PCB to face plate (per arm; ×4 arms = 16 total) | +| 4 | M3×30 SHCS | RPLIDAR ring to platform (through grommet) | +| 4 | M3 anti-vibration grommet | Silicone, M3, Ø6 | Between platform and RPLIDAR ring | +| 1 | 1/4-20 hex nut | Captured in RealSense bracket | +| 2 | M4 hex nut | Captured in collar rear half | +| 8 | M4 flat washer | Under head of all M4 bolts | + +--- + +## Print Settings + +| Part | Material | Infill | Perimeters | Notes | +|------|----------|--------|-----------|-------| +| collar_half (×2) | PETG | 40% | 5 | Flat-face-down; print support-free | +| platform | PETG or PLA | 30% | 4 | Top-face-up | +| rplidar_ring | PETG | 30% | 3 | Flat | +| realsense_bracket | PETG | 35% | 4 | Base on bed; arm horizontal | +| imx219_arm (×4) | PETG or PLA | 30% | 3 | Flat, arm along X | -- 2.47.2