saltylab-firmware/chassis/gopro_mount.scad
sl-mechanical e22fd23f33 feat: Add Issue #195 - GoPro mount adapter for T-slot sensor rail
Add gopro_mount.scad with:
- Standard GoPro 3-prong interface on top for HERO 5+ compatibility
- T-slot 2020 clamp with M3 thumbscrew retention (no tools required)
- Tilt mechanism: 0-90° with 15° detent angles (7 positions)
- Integrated T-nut slides into rail groove
- Rotation axis via M5 hinge pin with index-hole angle locking
- Design supports flat-face-down printing, no supports needed

Includes comprehensive BOM with:
- Part specifications for base clamp and camera bracket
- Fastener list and torque specs
- Step-by-step assembly instructions
- Tilt angle reference guide
- Post-print finishing notes
- Cable management guidance

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 11:46:14 -05:00

257 lines
12 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.

// ============================================================
// gopro_mount.scad — GoPro 3-Prong T-Slot Sensor Rail Mount
// Issue: #195 Agent: sl-mechanical Date: 2026-03-02
// ============================================================
//
// Universal GoPro camera mount for sensor_rail.scad (T-slot 2020).
//
// Top interface: Standard GoPro 3-prong (HERO 5+)
// Prongs slide into standard GoPro accessories.
// No additional clips or fasteners needed.
//
// Bottom clamp: T-slot 20×20 mm rail system (OpenBuilds compatible).
// M3 thumbscrew retention + M5 index holes for 15° detents.
//
// Tilt mechanism: Rotating hinge bracket allows camera tilt 0°90° from
// horizontal, locked at 15° increments via index holes.
// Rotation axis is perpendicular to rail (about Y-axis).
//
// Assembly:
// 1. Print gopro_mount_base (single part, flat-side-down, no supports)
// 2. Slide built-in T-nut into rail T-groove
// 3. Clamp with M3 thumbscrew from outside rail face
// 4. Rotate camera to desired tilt angle (0°, 15°, 30°, ... 90°)
// 5. Insert M5 alignment pin to lock tilt
//
// RENDER options:
// "mount" assembled mount view (default)
// "base_stl" base clamp for slicing (print flat)
// "camera_bracket" rotatable camera bracket for slicing
// ============================================================
RENDER = "mount";
// ── GoPro 3-prong interface (top) ──────────────────────────
// Standard GoPro HERO 5+ 3-prong attachment point.
// Overall footprint ~43×25 mm, 3 prongs slide into camera mounting slot.
GOPRO_WIDTH = 43.0; // front-to-back along camera face
GOPRO_DEPTH = 25.0; // left-to-right width
GOPRO_PRONG_H = 5.0; // height of prongs above base
GOPRO_PRONG_D = 4.0; // diameter/thickness of each prong
GOPRO_PRONG_SP = 14.0; // spacing between outer prongs (centre-to-centre)
// Centre prong is at Y=0; outer prongs at Y±GOPRO_PRONG_SP/2
// Prongs extend upward (+Z direction)
// ── T-slot clamp (bottom) ──────────────────────────────────
// Matches sensor_rail.scad T-slot 2020 dimensions.
RAIL_W = 20.0; // rail outer width/height
SLOT_INNER_W = 10.2; // T-groove inner width
SLOT_INNER_H = 5.8; // T-groove inner height (depth)
SLOT_NECK_H = 3.2; // distance from outer face to T-groove
TNUT_W = 9.8; // printable T-nut width (SLOT_INNER_W - 0.4)
TNUT_H = 5.5; // printable T-nut height (SLOT_INNER_H - 0.3)
TNUT_L = 12.0; // T-nut body length
TNUT_BOLT_D = 3.3; // M3 clearance bore through T-nut
THUMB_D = 16.0; // thumbwheel OD (visual only)
THUMB_H = 8.0; // thumbwheel height
// Index hole pitch for tilt detents
INDEX_PITCH = 25.0; // 25 mm spacing on rail
TILT_ANGLE_STEP = 15.0; // 15° tilt detents (0°, 15°, 30°, ... 90°)
M5_INDEX_D = 5.3; // M5 clearance hole diameter
// ── Rotation/tilt mechanism ───────────────────────────────
// Camera bracket rotates about Y-axis relative to base.
// Rotation axis is at the rail clamp interface (Z=0, Y=0).
// Tilt range: 0° to 90°.
MAX_TILT_DEG = 90.0; // maximum tilt angle
// Hinge pin: M5 bolt passes through base and camera bracket
HINGE_PIN_D = 5.3; // M5 bolt clearance
HINGE_PIN_L = 25.0; // pin length (accommodates rail width + brackets)
// ── General ────────────────────────────────────────────────
$fn = 64;
e = 0.01;
// ─────────────────────────────────────────────────────────────
// gopro_mount_base()
// T-slot clamp bracket with integrated T-nut.
// Mounted at bottom, rail clamp at Z=0 face.
// Hinge pin axis at Y=0, rotates camera bracket ±X.
//
// Print: flat-side-down (rail face down), no supports needed.
// ─────────────────────────────────────────────────────────────
module gopro_mount_base() {
clamp_h = RAIL_W + 8.0; // total clamp height
clamp_w = TNUT_L + 8.0; // clamp width (along rail)
clamp_d = 18.0; // clamp depth (front-to-back)
difference() {
union() {
// Main clamp body
translate([-clamp_w/2, -clamp_d/2, 0])
cube([clamp_w, clamp_d, clamp_h]);
// T-nut integration: slot to hold T-nut at rail interface
// T-nut sits in T-groove when rail is inserted from above
translate([-TNUT_L/2, -TNUT_W/2, SLOT_NECK_H])
cube([TNUT_L, TNUT_W, TNUT_H]);
// Hinge boss (supports rotation axis pin)
translate([-HINGE_PIN_L/2 - 2, -8, clamp_h - 4])
cube([HINGE_PIN_L + 4, 4, 4]);
}
// Rail bore (25.4 mm) — matches stem adapter pattern
// When rail is vertical, this bore slides onto rail extrusion
translate([0, 0, -e])
cylinder(d=RAIL_W + 0.4, h=clamp_h + 2*e);
// T-nut through-bolt (M3 thumbscrew hole)
// Bolt comes from outside rail face, through T-nut, clamping it
translate([0, 0, SLOT_NECK_H + TNUT_H/2])
rotate([90, 0, 0])
cylinder(d=TNUT_BOLT_D, h=clamp_d + 2*e);
// Hinge pin (M5) passes through base to camera bracket
translate([-HINGE_PIN_L/2, 0, clamp_h - 2])
rotate([0, 90, 0])
cylinder(d=HINGE_PIN_D, h=HINGE_PIN_L + 2*e);
// Index hole pockets for tilt angle lock (M5)
// One index hole on each side to lock camera tilt
for (angle = [0 : TILT_ANGLE_STEP : MAX_TILT_DEG]) {
// Holes are radially spaced around the hinge axis
y_offset = (HINGE_PIN_L/2 - 2) * sin(angle);
z_offset = clamp_h - 2 - (HINGE_PIN_L/2 - 2) * (1 - cos(angle));
translate([0, y_offset, z_offset])
cylinder(d=M5_INDEX_D, h=4, center=false);
}
// Vent slots (optional, aesthetic + weight reduction)
for (dz = [4, 8, 12])
translate([-clamp_w/2 + 2, -clamp_d/2 - e, dz])
cube([clamp_w - 4, 2, 1.5]);
}
}
// ─────────────────────────────────────────────────────────────
// gopro_camera_bracket()
// Rotatable bracket that holds GoPro camera via 3-prong mount.
// Rotates about Y-axis (hinge pin), tilt 0°90°.
//
// Hinge pin (M5 bolt) enters from base and locks bracket rotation.
// Index hole on bracket aligns with base index holes at each 15° step.
//
// Print: flat-side-down (prong face down), no supports.
// ─────────────────────────────────────────────────────────────
module gopro_camera_bracket() {
bracket_h = GOPRO_WIDTH + 8.0; // height when vertical
bracket_w = GOPRO_DEPTH + 6.0; // width (left-right)
bracket_t = 4.0; // bracket thickness
difference() {
union() {
// Main bracket body
translate([-bracket_w/2, -bracket_t/2, 0])
cube([bracket_w, bracket_t, bracket_h]);
// Hinge pivot boss
translate([-HINGE_PIN_L/2 - 2, 0, bracket_h - 4])
cube([HINGE_PIN_L + 4, bracket_t, 4]);
// GoPro prong mounting boss
translate([-GOPRO_DEPTH/2, 0, bracket_h - GOPRO_WIDTH/2])
cube([GOPRO_DEPTH, bracket_t + 2, GOPRO_WIDTH]);
}
// Hinge pin bore (M5)
translate([-HINGE_PIN_L/2, 0, bracket_h - 2])
rotate([0, 90, 0])
cylinder(d=HINGE_PIN_D + 0.2, h=HINGE_PIN_L + 2*e);
// Index hole (M5) for angle lock
// Bracket has one index hole that aligns with base holes at tilt angles
translate([GOPRO_DEPTH/2 + 1, 0, bracket_h - 4])
cylinder(d=M5_INDEX_D, h=bracket_t + 2*e);
// GoPro prong socket (3 mounting prongs)
// Centre prong at Y=0, outer prongs at Y±GOPRO_PRONG_SP/2
for (dy = [0, GOPRO_PRONG_SP/2, -GOPRO_PRONG_SP/2]) {
translate([0, bracket_t + e, bracket_h - GOPRO_WIDTH/2 + 5 - dy])
rotate([90, 0, 0])
cylinder(d=GOPRO_PRONG_D + 0.4, h=4);
}
}
}
// ─────────────────────────────────────────────────────────────
// gopro_prong_interface()
// Visual representation of the 3 prongs that camera mounts to.
// Not printed; shown during assembly view.
// ─────────────────────────────────────────────────────────────
module gopro_prong_interface() {
bracket_h = GOPRO_WIDTH + 8.0;
bracket_w = GOPRO_DEPTH + 6.0;
// 3 cylindrical prongs
for (dy = [0, GOPRO_PRONG_SP/2, -GOPRO_PRONG_SP/2]) {
translate([0, bracket_w/2 + 0.5, bracket_h - GOPRO_WIDTH/2 + 5 - dy])
rotate([90, 0, 0])
cylinder(d=GOPRO_PRONG_D, h=GOPRO_PRONG_H, $fn=32);
}
}
// ─────────────────────────────────────────────────────────────
// Assembly view: base + rotatable camera bracket
// ─────────────────────────────────────────────────────────────
module gopro_mount_assembly() {
// Base clamp (fixed)
color("SteelBlue", 0.9)
gopro_mount_base();
// Camera bracket (rotatable, at 45° tilt for visualization)
color("CornflowerBlue", 0.85)
rotate([0, 45, 0])
translate([0, 0, RAIL_W + 8])
gopro_camera_bracket();
// Visual GoPro prongs
color("LightSteelBlue", 0.7)
rotate([0, 45, 0])
translate([0, 0, RAIL_W + 8])
gopro_prong_interface();
// Phantom M5 hinge pin (visual reference)
color("Silver", 0.5)
translate([-HINGE_PIN_L/2, 0, RAIL_W + 8 - 2])
rotate([0, 90, 0])
cylinder(d=5, h=HINGE_PIN_L);
}
// ─────────────────────────────────────────────────────────────
// Render selector
// ─────────────────────────────────────────────────────────────
if (RENDER == "mount") {
gopro_mount_assembly();
} else if (RENDER == "base_stl") {
// Flat print orientation: rail-facing side down
rotate([180, 0, 0])
translate([0, 0, -RAIL_W - 8])
gopro_mount_base();
} else if (RENDER == "camera_bracket") {
// Flat print orientation: prong-facing side down
rotate([0, 0, 0])
translate([0, 0, GOPRO_WIDTH + 14])
rotate([180, 0, 0])
gopro_camera_bracket();
}