feat: Camera gimbal mount for RealSense D435i (Issue #552) #556
599
chassis/gimbal_camera_mount.scad
Normal file
599
chassis/gimbal_camera_mount.scad
Normal file
@ -0,0 +1,599 @@
|
||||
// ============================================================
|
||||
// gimbal_camera_mount.scad — Pan/Tilt Gimbal Mount for RealSense D435i
|
||||
// Issue: #552 Agent: sl-mechanical Date: 2026-03-14
|
||||
// ============================================================
|
||||
//
|
||||
// Parametric gimbal bracket system mounting an Intel RealSense D435i
|
||||
// (or similar box camera) on a 2-axis pan/tilt gimbal driven by
|
||||
// ST3215 serial bus servos (25T spline, Feetech/Waveshare).
|
||||
//
|
||||
// Architecture:
|
||||
// Pan axis — base T-nut clamps to 2020 rail; pan servo rotates yoke
|
||||
// Tilt axis — tilt servo horn plate bolts to ST3215 horn; camera cradle
|
||||
// rocks on tilt axis
|
||||
// Camera — D435i captured via 1/4-20 UNC hex nut in cradle floor
|
||||
// Damping — PETG flexure ribs on camera contact faces (or TPU pads)
|
||||
// Wiring — USB-C cable routed through channel in cradle arm
|
||||
//
|
||||
// Part catalogue:
|
||||
// Part 1 — tnut_rail_base() 2020 rail T-nut base + pan servo seat
|
||||
// Part 2 — pan_yoke() U-yoke connecting pan servo to tilt axis
|
||||
// Part 3 — tilt_horn_plate() Plate bolting to ST3215 tilt servo horn
|
||||
// Part 4 — camera_cradle() D435i cradle with 1/4-20 captured nut
|
||||
// Part 5 — vibe_pad() PETG flexure vibration-damping pad (×2)
|
||||
// Part 6 — assembly_preview() Full assembly preview
|
||||
//
|
||||
// Hardware BOM (per gimbal):
|
||||
// 2× ST3215 serial bus servo (pan + tilt)
|
||||
// 2× servo horn (25T spline, ≥Ø36 mm, 4× M3 bolt holes on Ø24 mm BC)
|
||||
// 2× M3 × 8 mm SHCS horn-to-plate bolts (×4 each horn = 8 total)
|
||||
// 1× M3 × 16 mm SHCS + nut T-nut rail clamp thumbscrew
|
||||
// 1× 1/4-20 UNC × 8 mm SHCS camera retention bolt (or existing tripod screw)
|
||||
// 1× 1/4-20 UNC hex nut captured in cradle floor
|
||||
// 4× M3 × 12 mm SHCS yoke-to-tilt-plate pivot axle bolts
|
||||
// 2× M3 × 25 mm SHCS pan yoke attachment to servo body
|
||||
// (optional) 2× vibe_pad printed in TPU 95A
|
||||
//
|
||||
// ST3215 servo interface (caliper-verified Feetech ST3215):
|
||||
// Body footprint : 40.0 × 20.0 mm (W × D), 36.5 mm tall
|
||||
// Shaft centre H : 28.5 mm from mounting face
|
||||
// Shaft spline : 25T, centre Ø5.8 mm, D-cut
|
||||
// Mount holes : 4× M3 on 32 × 10 mm rectangular pattern (18 mm offset)
|
||||
// Horn bolt circle: Ø24 mm, 4× M3
|
||||
// Horn OD : ~36 mm
|
||||
//
|
||||
// D435i camera interface (caliper-verified):
|
||||
// Body : 90 × 25 × 25 mm (W × D × H)
|
||||
// Tripod thread : 1/4-20 UNC, centred bottom face, 9 mm from front
|
||||
// USB-C connector: right rear, 8 × 5 mm opening, 4 mm from edge
|
||||
//
|
||||
// Parametric camera size (override to adapt to other cameras):
|
||||
// CAM_W, CAM_D, CAM_H — body envelope
|
||||
// CAM_MOUNT_X — tripod hole X offset from camera centre
|
||||
// CAM_MOUNT_Y — tripod hole Y offset from front face
|
||||
//
|
||||
// Coordinate convention:
|
||||
// Camera looks in +Y direction (forward)
|
||||
// Pan axis is Z (vertical); tilt axis is X (lateral)
|
||||
// Rail runs along Z; T-nut base at Z=0
|
||||
// All parts at assembly origin; translate for assembly_preview
|
||||
//
|
||||
// RENDER options:
|
||||
// "assembly" full assembly preview (default)
|
||||
// "tnut_rail_base_stl" Part 1
|
||||
// "pan_yoke_stl" Part 2
|
||||
// "tilt_horn_plate_stl" Part 3
|
||||
// "camera_cradle_stl" Part 4
|
||||
// "vibe_pad_stl" Part 5
|
||||
//
|
||||
// Export commands:
|
||||
// openscad gimbal_camera_mount.scad -D 'RENDER="tnut_rail_base_stl"' -o gcm_tnut_base.stl
|
||||
// openscad gimbal_camera_mount.scad -D 'RENDER="pan_yoke_stl"' -o gcm_pan_yoke.stl
|
||||
// openscad gimbal_camera_mount.scad -D 'RENDER="tilt_horn_plate_stl"' -o gcm_tilt_horn_plate.stl
|
||||
// openscad gimbal_camera_mount.scad -D 'RENDER="camera_cradle_stl"' -o gcm_camera_cradle.stl
|
||||
// openscad gimbal_camera_mount.scad -D 'RENDER="vibe_pad_stl"' -o gcm_vibe_pad.stl
|
||||
// ============================================================
|
||||
|
||||
$fn = 64;
|
||||
e = 0.01; // epsilon for boolean clearance
|
||||
|
||||
// ── Parametric camera envelope ────────────────────────────────────────────────
|
||||
// Override these for cameras other than D435i
|
||||
CAM_W = 90.0; // camera body width (X)
|
||||
CAM_D = 25.0; // camera body depth (Y)
|
||||
CAM_H = 25.0; // camera body height (Z)
|
||||
CAM_MOUNT_X = 0.0; // tripod hole X offset from camera body centre
|
||||
CAM_MOUNT_Y = 9.0; // tripod hole from front face (Y) [D435i: 9 mm]
|
||||
CAM_USBC_X = CAM_W/2 - 4; // USB-C connector X (right side)
|
||||
CAM_USBC_Z = CAM_H/2; // USB-C connector Z (mid-height rear)
|
||||
CAM_USBC_W = 9.0; // USB-C opening width (X)
|
||||
CAM_USBC_H = 5.0; // USB-C opening height (Z)
|
||||
|
||||
// ── Rail geometry (matches sensor_rail.scad / sensor_rail_brackets.scad) ─────
|
||||
RAIL_W = 20.0;
|
||||
SLOT_OPEN = 6.0;
|
||||
SLOT_INNER_W = 10.2;
|
||||
SLOT_INNER_H = 5.8;
|
||||
SLOT_NECK_H = 3.2;
|
||||
|
||||
// ── T-nut geometry (matches sensor_rail_brackets.scad) ───────────────────────
|
||||
TNUT_W = 9.8;
|
||||
TNUT_H = 5.5;
|
||||
TNUT_L = 12.0;
|
||||
TNUT_M3_NUT_AF = 5.5;
|
||||
TNUT_M3_NUT_H = 2.5;
|
||||
TNUT_BOLT_D = 3.3; // M3 clearance
|
||||
|
||||
// ── T-nut base plate geometry ─────────────────────────────────────────────────
|
||||
BASE_W = 44.0; // wide enough for pan servo body (40 mm)
|
||||
BASE_H = 40.0; // height along rail (Z)
|
||||
BASE_T = SLOT_NECK_H + 2.0; // plate depth (Y), rail-face side
|
||||
|
||||
// ── ST3215 servo geometry ─────────────────────────────────────────────────────
|
||||
SERVO_W = 40.0; // servo body width (X)
|
||||
SERVO_D = 20.0; // servo body depth (Y)
|
||||
SERVO_H = 36.5; // servo body height (Z)
|
||||
SERVO_SHAFT_Z = 28.5; // shaft centre height from mounting face
|
||||
SERVO_HOLE_X = 16.0; // mount hole half-span X (32 mm span)
|
||||
SERVO_HOLE_Y = 5.0; // mount hole half-span Y (10 mm span)
|
||||
SERVO_M3_D = 3.3; // M3 clearance
|
||||
|
||||
// ── Servo horn geometry ───────────────────────────────────────────────────────
|
||||
HORN_OD = 36.0; // horn outer diameter
|
||||
HORN_SPLINE_D = 5.9; // 25T spline bore clearance (5.8 + 0.1)
|
||||
HORN_BC_D = 24.0; // bolt circle diameter (4× M3)
|
||||
HORN_BOLT_D = 3.3; // M3 clearance through horn plate
|
||||
HORN_PLATE_T = 5.0; // tilt horn plate thickness
|
||||
|
||||
// ── Yoke geometry ─────────────────────────────────────────────────────────────
|
||||
YOKE_WALL_T = 5.0; // yoke arm wall thickness
|
||||
YOKE_ARM_H = 50.0; // yoke arm height (Z) — clears servo body + camera
|
||||
YOKE_INNER_W = CAM_W + 8.0; // yoke inner span (camera + pad clearance)
|
||||
YOKE_BASE_T = 8.0; // yoke base plate thickness
|
||||
|
||||
// ── Tilt pivot ────────────────────────────────────────────────────────────────
|
||||
PIVOT_D = 4.3; // M4 pivot axle bore
|
||||
PIVOT_BOSS_D = 10.0; // boss OD around pivot bore
|
||||
PIVOT_BOSS_L = 6.0; // boss protrusion from yoke wall
|
||||
|
||||
// ── Camera cradle geometry ────────────────────────────────────────────────────
|
||||
CRADLE_WALL_T = 4.0; // cradle side wall thickness
|
||||
CRADLE_FLOOR_T = 5.0; // cradle floor thickness (holds 1/4-20 nut)
|
||||
CRADLE_LIP_T = 3.0; // front retaining lip thickness
|
||||
CRADLE_LIP_H = 8.0; // front lip height
|
||||
CABLE_CH_W = 12.0; // USB-C cable channel width
|
||||
CABLE_CH_H = 8.0; // USB-C cable channel height
|
||||
|
||||
// ── 1/4-20 UNC tripod thread ──────────────────────────────────────────────────
|
||||
QTR20_D = 6.6; // 1/4-20 clearance bore
|
||||
QTR20_NUT_AF = 11.1; // 1/4-20 hex nut across-flats (standard)
|
||||
QTR20_NUT_H = 5.5; // 1/4-20 hex nut height
|
||||
|
||||
// ── Vibration-damping pad geometry ────────────────────────────────────────────
|
||||
PAD_W = CAM_W - 2*CRADLE_WALL_T - 2;
|
||||
PAD_H = CAM_H + 4;
|
||||
PAD_T = 2.5; // pad body thickness
|
||||
RIB_H = 1.5; // flexure rib height
|
||||
RIB_W = 1.2; // rib width
|
||||
RIB_PITCH = 5.0; // rib pitch
|
||||
|
||||
// ── Fastener sizes ────────────────────────────────────────────────────────────
|
||||
M3_D = 3.3;
|
||||
M4_D = 4.3;
|
||||
M3_NUT_AF = 5.5;
|
||||
M3_NUT_H = 2.4;
|
||||
|
||||
// ============================================================
|
||||
// RENDER DISPATCH
|
||||
// ============================================================
|
||||
RENDER = "assembly";
|
||||
|
||||
if (RENDER == "assembly") assembly_preview();
|
||||
else if (RENDER == "tnut_rail_base_stl") tnut_rail_base();
|
||||
else if (RENDER == "pan_yoke_stl") pan_yoke();
|
||||
else if (RENDER == "tilt_horn_plate_stl") tilt_horn_plate();
|
||||
else if (RENDER == "camera_cradle_stl") camera_cradle();
|
||||
else if (RENDER == "vibe_pad_stl") vibe_pad();
|
||||
|
||||
// ============================================================
|
||||
// ASSEMBLY PREVIEW
|
||||
// ============================================================
|
||||
module assembly_preview() {
|
||||
asm_rail_z = 0;
|
||||
// Rail section ghost (200 mm)
|
||||
%color("Silver", 0.25)
|
||||
translate([-RAIL_W/2, -RAIL_W/2, asm_rail_z])
|
||||
cube([RAIL_W, RAIL_W, 200]);
|
||||
|
||||
// T-nut rail base
|
||||
color("OliveDrab", 0.85)
|
||||
translate([0, 0, asm_rail_z + 80])
|
||||
tnut_rail_base();
|
||||
|
||||
// Pan servo ghost (sitting in base seat)
|
||||
%color("DimGray", 0.4)
|
||||
translate([-SERVO_W/2, BASE_T, asm_rail_z + 80 + (BASE_H - SERVO_H)/2])
|
||||
cube([SERVO_W, SERVO_D, SERVO_H]);
|
||||
|
||||
// Pan yoke rising from servo shaft
|
||||
color("SteelBlue", 0.85)
|
||||
translate([0, BASE_T + SERVO_D, asm_rail_z + 80 + BASE_H/2])
|
||||
pan_yoke();
|
||||
|
||||
// Tilt horn plate (tilt axis — left yoke wall)
|
||||
color("DarkOrange", 0.85)
|
||||
translate([-YOKE_INNER_W/2 - YOKE_WALL_T - HORN_PLATE_T,
|
||||
BASE_T + SERVO_D + YOKE_BASE_T,
|
||||
asm_rail_z + 80 + BASE_H/2 + YOKE_ARM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
tilt_horn_plate();
|
||||
|
||||
// Camera cradle (centred in yoke)
|
||||
color("DarkSlateGray", 0.85)
|
||||
translate([0, BASE_T + SERVO_D + YOKE_BASE_T + CRADLE_FLOOR_T,
|
||||
asm_rail_z + 80 + BASE_H/2 + YOKE_ARM_H/2 - CAM_H/2])
|
||||
camera_cradle();
|
||||
|
||||
// D435i ghost
|
||||
%color("Black", 0.4)
|
||||
translate([-CAM_W/2,
|
||||
BASE_T + SERVO_D + YOKE_BASE_T + CRADLE_FLOOR_T + PAD_T,
|
||||
asm_rail_z + 80 + Base_H_mid() - CAM_H/2])
|
||||
cube([CAM_W, CAM_D, CAM_H]);
|
||||
|
||||
// Vibe pads (front + rear camera face)
|
||||
color("DimGray", 0.80) {
|
||||
translate([-CAM_W/2 + CRADLE_WALL_T + 1,
|
||||
Base_T + SERVO_D + YOKE_BASE_T + CRADLE_FLOOR_T,
|
||||
asm_rail_z + 80 + Base_H_mid() - PAD_H/2])
|
||||
rotate([90, 0, 0])
|
||||
vibe_pad();
|
||||
}
|
||||
}
|
||||
|
||||
// helper (avoids recomputing same expression)
|
||||
function Base_T() = BASE_T;
|
||||
function Base_H_mid() = BASE_H/2 + YOKE_ARM_H/2;
|
||||
|
||||
// ============================================================
|
||||
// PART 1 — T-NUT RAIL BASE (pan servo seat + rail clamp)
|
||||
// ============================================================
|
||||
// Mounts to 2020 rail via standard T-nut tongue.
|
||||
// Front face (+Y side) provides flat seat for pan ST3215 servo body.
|
||||
// Servo body recessed 1 mm into seat for positive lateral registration.
|
||||
// Pan servo shaft axis = Z (vertical) → pan rotation about Z.
|
||||
//
|
||||
// Print: PETG, 5 perims, 50 % gyroid. Orient face-plate down (flat).
|
||||
module tnut_rail_base() {
|
||||
difference() {
|
||||
union() {
|
||||
// ── Face plate (against rail outer face, -Y side) ────────────
|
||||
translate([-BASE_W/2, -BASE_T, 0])
|
||||
cube([BASE_W, BASE_T, BASE_H]);
|
||||
|
||||
// ── T-nut neck (enters rail slot, +Y side of face plate) ─────
|
||||
translate([-TNUT_W/2, 0, (BASE_H - TNUT_L)/2])
|
||||
cube([TNUT_W, SLOT_NECK_H + e, TNUT_L]);
|
||||
|
||||
// ── T-nut inner body (wider, locks inside T-groove) ──────────
|
||||
translate([-TNUT_W/2, SLOT_NECK_H - e, (BASE_H - TNUT_L)/2])
|
||||
cube([TNUT_W, TNUT_H - SLOT_NECK_H + e, TNUT_L]);
|
||||
|
||||
// ── Pan servo seat boss (front face, +Y side) ────────────────
|
||||
// Proud pad that servo body sits on; 1 mm registration recess
|
||||
translate([-BASE_W/2, -BASE_T, 0])
|
||||
cube([BASE_W, BASE_T + 6, BASE_H]);
|
||||
}
|
||||
|
||||
// ── Rail clamp bolt bore (M3 through face plate) ─────────────────
|
||||
translate([0, -BASE_T - e, BASE_H/2])
|
||||
rotate([-90, 0, 0])
|
||||
cylinder(d = TNUT_BOLT_D, h = BASE_T + TNUT_H + 2*e);
|
||||
|
||||
// ── M3 hex nut pocket (inside T-nut body) ────────────────────────
|
||||
translate([0, SLOT_NECK_H + 0.3, BASE_H/2])
|
||||
rotate([-90, 0, 0])
|
||||
cylinder(d = TNUT_M3_NUT_AF / cos(30),
|
||||
h = TNUT_M3_NUT_H + 0.3, $fn = 6);
|
||||
|
||||
// ── Servo body recess (1 mm registration pocket in seat face) ────
|
||||
translate([-SERVO_W/2 - 0.3, -BASE_T + 6 - 1.0,
|
||||
(BASE_H - SERVO_H)/2 - 0.3])
|
||||
cube([SERVO_W + 0.6, 1.2, SERVO_H + 0.6]);
|
||||
|
||||
// ── Pan servo mount holes (4× M3 in rectangular pattern) ─────────
|
||||
for (sx = [-SERVO_HOLE_X, SERVO_HOLE_X])
|
||||
for (sy = [-SERVO_HOLE_Y, SERVO_HOLE_Y])
|
||||
translate([sx, -BASE_T + 6 + e, BASE_H/2 + sy])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = SERVO_M3_D, h = BASE_T + 2*e);
|
||||
|
||||
// ── Pan servo shaft bore (passes shaft through base if needed) ────
|
||||
// Centre of shaft at Z = BASE_H/2, no bore needed (shaft exits top)
|
||||
|
||||
// ── Lightening pockets ────────────────────────────────────────────
|
||||
translate([0, -BASE_T/2 + 3, BASE_H/2])
|
||||
cube([BASE_W - 14, BASE_T - 4, BASE_H - 14], center = true);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PART 2 — PAN YOKE
|
||||
// ============================================================
|
||||
// U-shaped yoke that attaches to pan servo horn (below) and carries
|
||||
// the tilt axis (above). Two vertical arms straddle the camera cradle.
|
||||
// Tilt servo sits on top of one arm; tilt pivot boss on the other.
|
||||
//
|
||||
// Yoke base bolts to pan servo horn (4× M3 on HORN_BC_D bolt circle).
|
||||
// Pan servo horn spline bore passes through yoke base centre.
|
||||
// Tilt axis: M4 pivot axle through boss on each arm (X-axis rotation).
|
||||
//
|
||||
// Print: upright (yoke in final orientation), PETG, 5 perims, 40% gyroid.
|
||||
module pan_yoke() {
|
||||
arm_z_total = YOKE_ARM_H + YOKE_BASE_T;
|
||||
inner_w = YOKE_INNER_W;
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// ── Yoke base plate (bolts to pan servo horn) ─────────────────
|
||||
translate([-inner_w/2 - YOKE_WALL_T, 0, 0])
|
||||
cube([inner_w + 2*YOKE_WALL_T, YOKE_BASE_T, YOKE_BASE_T]);
|
||||
|
||||
// ── Left arm ──────────────────────────────────────────────────
|
||||
translate([-inner_w/2 - YOKE_WALL_T, 0, 0])
|
||||
cube([YOKE_WALL_T, YOKE_BASE_T, arm_z_total]);
|
||||
|
||||
// ── Right arm (tilt servo side) ───────────────────────────────
|
||||
translate([inner_w/2, 0, 0])
|
||||
cube([YOKE_WALL_T, YOKE_BASE_T, arm_z_total]);
|
||||
|
||||
// ── Tilt pivot bosses (both arms, X-axis) ─────────────────────
|
||||
// Left pivot boss (plain pivot — M4 bolt)
|
||||
translate([-inner_w/2 - YOKE_WALL_T - PIVOT_BOSS_L,
|
||||
YOKE_BASE_T/2,
|
||||
YOKE_BASE_T + YOKE_ARM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = PIVOT_BOSS_D, h = PIVOT_BOSS_L + YOKE_WALL_T);
|
||||
|
||||
// Right pivot boss (tilt servo horn seat)
|
||||
translate([inner_w/2,
|
||||
YOKE_BASE_T/2,
|
||||
YOKE_BASE_T + YOKE_ARM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = PIVOT_BOSS_D + 4, h = PIVOT_BOSS_L + YOKE_WALL_T);
|
||||
|
||||
// ── Tilt servo body seat on right arm top ─────────────────────
|
||||
translate([inner_w/2, 0, arm_z_total - SERVO_H - 4])
|
||||
cube([YOKE_WALL_T + SERVO_D + 2, YOKE_BASE_T, SERVO_H + 4]);
|
||||
}
|
||||
|
||||
// ── Pan horn spline bore (centre of yoke base) ────────────────────
|
||||
translate([0, YOKE_BASE_T/2, YOKE_BASE_T/2])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = HORN_SPLINE_D, h = YOKE_BASE_T + 2*e,
|
||||
center = true);
|
||||
|
||||
// ── Pan horn bolt holes (4× M3 on HORN_BC_D) ─────────────────────
|
||||
for (a = [45, 135, 225, 315])
|
||||
translate([HORN_BC_D/2 * cos(a),
|
||||
YOKE_BASE_T/2,
|
||||
HORN_BC_D/2 * sin(a) + YOKE_BASE_T/2])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = HORN_BOLT_D, h = YOKE_BASE_T + 2*e,
|
||||
center = true);
|
||||
|
||||
// ── Left tilt pivot bore (M4 clearance) ───────────────────────────
|
||||
translate([-inner_w/2 - YOKE_WALL_T - PIVOT_BOSS_L - e,
|
||||
YOKE_BASE_T/2,
|
||||
YOKE_BASE_T + YOKE_ARM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = PIVOT_D, h = PIVOT_BOSS_L + YOKE_WALL_T + 2*e);
|
||||
|
||||
// ── Right tilt pivot bore (larger — tilt horn plate seats here) ───
|
||||
translate([inner_w/2 - e,
|
||||
YOKE_BASE_T/2,
|
||||
YOKE_BASE_T + YOKE_ARM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = HORN_SPLINE_D,
|
||||
h = PIVOT_BOSS_L + YOKE_WALL_T + 2*e);
|
||||
|
||||
// ── Tilt servo mount holes in right arm seat ──────────────────────
|
||||
for (sz = [-SERVO_HOLE_Y, SERVO_HOLE_Y])
|
||||
translate([inner_w/2 + YOKE_WALL_T + SERVO_D/2,
|
||||
YOKE_BASE_T/2,
|
||||
arm_z_total - SERVO_H/2 + sz])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = SERVO_M3_D, h = YOKE_BASE_T + 2*e,
|
||||
center = true);
|
||||
|
||||
// ── M3 nut pockets (tilt servo mount, rear of arm seat) ──────────
|
||||
for (sz = [-SERVO_HOLE_Y, SERVO_HOLE_Y])
|
||||
translate([inner_w/2 + YOKE_WALL_T + SERVO_D/2,
|
||||
YOKE_BASE_T - M3_NUT_H - 0.5,
|
||||
arm_z_total - SERVO_H/2 + sz])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = M3_NUT_AF / cos(30), h = M3_NUT_H + 0.5,
|
||||
$fn = 6);
|
||||
|
||||
// ── Lightening slots in yoke arms ─────────────────────────────────
|
||||
translate([-inner_w/2 - YOKE_WALL_T/2,
|
||||
YOKE_BASE_T/2,
|
||||
YOKE_BASE_T + YOKE_ARM_H/2 - 10])
|
||||
cube([YOKE_WALL_T - 2, YOKE_BASE_T - 2, YOKE_ARM_H - 24],
|
||||
center = true);
|
||||
translate([inner_w/2 + YOKE_WALL_T/2,
|
||||
YOKE_BASE_T/2,
|
||||
YOKE_BASE_T + YOKE_ARM_H/2 - 10])
|
||||
cube([YOKE_WALL_T - 2, YOKE_BASE_T - 2, YOKE_ARM_H - 30],
|
||||
center = true);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PART 3 — TILT HORN PLATE
|
||||
// ============================================================
|
||||
// Disc plate bolting to tilt ST3215 servo horn on the right yoke arm.
|
||||
// Servo horn spline centres into disc bore (captured, no free rotation).
|
||||
// Camera cradle attaches to opposite face via 2× M3 bolts.
|
||||
//
|
||||
// Tilt range: ±45° limited by yoke arm geometry.
|
||||
// Plate thickness HORN_PLATE_T provides stiffness for cantilevered cradle.
|
||||
//
|
||||
// Print: flat (disc face down), PETG, 5 perims, 50 % infill.
|
||||
module tilt_horn_plate() {
|
||||
plate_od = HORN_OD + 8; // plate OD (4 mm rim outside horn BC)
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// ── Main disc ─────────────────────────────────────────────────
|
||||
cylinder(d = plate_od, h = HORN_PLATE_T);
|
||||
|
||||
// ── Cradle attachment arm (extends to camera cradle) ──────────
|
||||
// Rectangular boss on top of disc toward camera
|
||||
translate([-CAM_W/2, HORN_PLATE_T - e, -CAM_H/2])
|
||||
cube([CAM_W, HORN_PLATE_T + 4, CAM_H]);
|
||||
}
|
||||
|
||||
// ── Servo horn spline bore (centre) ───────────────────────────────
|
||||
translate([0, 0, -e])
|
||||
cylinder(d = HORN_SPLINE_D, h = HORN_PLATE_T + 2*e);
|
||||
|
||||
// ── Horn bolt holes (4× M3 on HORN_BC_D) ─────────────────────────
|
||||
for (a = [45, 135, 225, 315])
|
||||
translate([HORN_BC_D/2 * cos(a),
|
||||
HORN_BC_D/2 * sin(a), -e])
|
||||
cylinder(d = HORN_BOLT_D, h = HORN_PLATE_T + 2*e);
|
||||
|
||||
// ── Pivot axle bore (M4, coaxial with horn centre) ────────────────
|
||||
translate([0, 0, -e])
|
||||
cylinder(d = PIVOT_D, h = HORN_PLATE_T + 2*e);
|
||||
|
||||
// ── Cradle attachment bolts (2× M3 in arm boss) ──────────────────
|
||||
for (cz = [-CAM_H/2 + 6, CAM_H/2 - 6])
|
||||
translate([0, HORN_PLATE_T + 2, cz])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = M3_D, h = HORN_PLATE_T + 6 + 2*e);
|
||||
|
||||
// ── M3 hex nut pockets (rear of disc face) ────────────────────────
|
||||
for (cz = [-CAM_H/2 + 6, CAM_H/2 - 6])
|
||||
translate([0, M3_NUT_H + 0.5, cz])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d = M3_NUT_AF / cos(30),
|
||||
h = M3_NUT_H + 0.5, $fn = 6);
|
||||
|
||||
// ── Weight-relief arcs (between horn bolt holes) ──────────────────
|
||||
for (a = [0, 90, 180, 270])
|
||||
translate([(plate_od/2 - 5) * cos(a),
|
||||
(plate_od/2 - 5) * sin(a), -e])
|
||||
cylinder(d = 6, h = HORN_PLATE_T + 2*e);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PART 4 — CAMERA CRADLE
|
||||
// ============================================================
|
||||
// Open-front U-cradle holding D435i via captured 1/4-20 hex nut.
|
||||
// Front lip retains camera from sliding forward (+Y).
|
||||
// Vibration-damping pads seat in recessed pockets on inner faces.
|
||||
// USB-C cable routing channel exits cradle right rear wall.
|
||||
//
|
||||
// 1/4-20 captured nut in cradle floor — tighten with standard
|
||||
// tripod screw or M6→1/4-20 adapter from camera bottom.
|
||||
//
|
||||
// Print: cradle-floor-down (flat), PETG, 5 perims, 40 % gyroid.
|
||||
// No supports needed (overhangs < 45°).
|
||||
module camera_cradle() {
|
||||
outer_w = CAM_W + 2*CRADLE_WALL_T;
|
||||
outer_h = CAM_H + CRADLE_FLOOR_T;
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// ── Cradle body ───────────────────────────────────────────────
|
||||
translate([-outer_w/2, 0, 0])
|
||||
cube([outer_w, CAM_D + CRADLE_WALL_T, outer_h]);
|
||||
|
||||
// ── Front retaining lip ───────────────────────────────────────
|
||||
translate([-outer_w/2, CAM_D + CRADLE_WALL_T - CRADLE_LIP_T, 0])
|
||||
cube([outer_w, CRADLE_LIP_T, CRADLE_LIP_H]);
|
||||
|
||||
// ── Cable channel boss (right rear, exits +X side) ────────────
|
||||
translate([CAM_W/2 + CRADLE_WALL_T - e,
|
||||
0,
|
||||
CRADLE_FLOOR_T + CAM_H/2 - CABLE_CH_H/2])
|
||||
cube([CABLE_CH_W + CRADLE_WALL_T, CAM_D * 0.6, CABLE_CH_H]);
|
||||
|
||||
// ── Tilt horn attachment tabs (left + right, bolt to horn plate)─
|
||||
for (sx = [-outer_w/2 - 4, outer_w/2])
|
||||
translate([sx, CAM_D/2, CRADLE_FLOOR_T + CAM_H/2 - 6])
|
||||
cube([4, 12, 12]);
|
||||
}
|
||||
|
||||
// ── Camera pocket (hollow interior) ──────────────────────────────
|
||||
translate([-CAM_W/2, 0, CRADLE_FLOOR_T])
|
||||
cube([CAM_W, CAM_D + CRADLE_WALL_T + e, CAM_H + e]);
|
||||
|
||||
// ── 1/4-20 UNC clearance bore (camera tripod thread, bottom) ─────
|
||||
translate([CAM_MOUNT_X, CAM_MOUNT_Y, -e])
|
||||
cylinder(d = QTR20_D, h = CRADLE_FLOOR_T + 2*e);
|
||||
|
||||
// ── 1/4-20 hex nut pocket (captured in cradle floor) ─────────────
|
||||
translate([CAM_MOUNT_X, CAM_MOUNT_Y, CRADLE_FLOOR_T - QTR20_NUT_H - 0.5])
|
||||
cylinder(d = QTR20_NUT_AF / cos(30),
|
||||
h = QTR20_NUT_H + 0.6, $fn = 6);
|
||||
|
||||
// ── USB-C cable channel (exit through right rear wall) ────────────
|
||||
translate([CAM_W/2 - e,
|
||||
0,
|
||||
CRADLE_FLOOR_T + CAM_H/2 - CABLE_CH_H/2])
|
||||
cube([CABLE_CH_W + CRADLE_WALL_T + 2*e,
|
||||
CAM_D * 0.6 + e, CABLE_CH_H]);
|
||||
|
||||
// ── Vibe pad recesses on inner camera-contact faces ───────────────
|
||||
// Rear wall recess (camera front face → +Y side of rear wall)
|
||||
translate([-CAM_W/2 + CRADLE_WALL_T, CRADLE_WALL_T, CRADLE_FLOOR_T])
|
||||
cube([CAM_W, PAD_T, CAM_H]);
|
||||
|
||||
// ── Tilt horn bolt holes in attachment tabs ───────────────────────
|
||||
for (sx = [-outer_w/2 - 4 - e, outer_w/2 - e])
|
||||
translate([sx, CAM_D/2 + 6, CRADLE_FLOOR_T + CAM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = M3_D, h = 6 + 2*e);
|
||||
|
||||
// ── M3 nut pockets in attachment tabs ─────────────────────────────
|
||||
translate([outer_w/2 + 4 - M3_NUT_H - 0.4,
|
||||
CAM_D/2 + 6,
|
||||
CRADLE_FLOOR_T + CAM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = M3_NUT_AF / cos(30),
|
||||
h = M3_NUT_H + 0.4, $fn = 6);
|
||||
translate([-outer_w/2 - 4 - e,
|
||||
CAM_D/2 + 6,
|
||||
CRADLE_FLOOR_T + CAM_H/2])
|
||||
rotate([0, 90, 0])
|
||||
cylinder(d = M3_NUT_AF / cos(30),
|
||||
h = M3_NUT_H + 0.4, $fn = 6);
|
||||
|
||||
// ── Lightening pockets in cradle walls ────────────────────────────
|
||||
for (face_x = [-CAM_W/2 - CRADLE_WALL_T - e, CAM_W/2 - e])
|
||||
translate([face_x, CAM_D * 0.2, CRADLE_FLOOR_T + 3])
|
||||
cube([CRADLE_WALL_T + 2*e, CAM_D * 0.55, CAM_H - 6]);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// PART 5 — VIBRATION-DAMPING PAD
|
||||
// ============================================================
|
||||
// Flat pad with transverse PETG flexure ribs pressing against camera body.
|
||||
// Rib geometry (thin fins ~1.5 mm tall) deflects under camera vibration,
|
||||
// attenuating high-frequency input from motor/drive-train.
|
||||
// For superior damping: print in TPU 95A (no infill changes needed).
|
||||
// Pads seat in recessed pockets in camera cradle inner wall.
|
||||
// Optional M2 bolt-through at corners or adhesive-back foam tape.
|
||||
//
|
||||
// Print: pad-back-face-down, PETG or TPU 95A, 3 perims, 20 % infill.
|
||||
module vibe_pad() {
|
||||
rib_count = floor((PAD_W - RIB_W) / RIB_PITCH);
|
||||
|
||||
union() {
|
||||
// ── Base plate ────────────────────────────────────────────────────
|
||||
translate([-PAD_W/2, -PAD_T, -PAD_H/2])
|
||||
cube([PAD_W, PAD_T, PAD_H]);
|
||||
|
||||
// ── Flexure ribs (parallel to Z, spaced RIB_PITCH apart) ─────────
|
||||
for (i = [0 : rib_count - 1]) {
|
||||
rx = -PAD_W/2 + RIB_PITCH/2 + i * RIB_PITCH + RIB_W/2;
|
||||
if (rx <= PAD_W/2 - RIB_W/2)
|
||||
translate([rx, 0, 0])
|
||||
cube([RIB_W, RIB_H, PAD_H - 6], center = true);
|
||||
}
|
||||
|
||||
// ── Corner nubs (M2 bolt-through retention, optional) ─────────────
|
||||
for (px = [-PAD_W/2 + 5, PAD_W/2 - 5])
|
||||
for (pz = [-PAD_H/2 + 5, PAD_H/2 - 5])
|
||||
translate([px, -PAD_T/2, pz])
|
||||
difference() {
|
||||
cylinder(d = 5, h = PAD_T, center = true);
|
||||
cylinder(d = 2.4, h = PAD_T + 2*e, center = true);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user