feat: Prototype base plate — real hub motor axle measurements #11
@ -1,6 +1,6 @@
|
||||
# SaltyBot Chassis — Bill of Materials
|
||||
**Task:** bd-1iy5 / prototype-baseplate
|
||||
**Rev:** B — 2026-02-28 (updated with caliper-verified axle measurements)
|
||||
**Rev:** C — 2026-02-28 (vertical stem architecture; batteries on mast carousel)
|
||||
**Agent:** sl-mechanical
|
||||
|
||||
---
|
||||
@ -29,15 +29,35 @@ PR #7 (`chassis_frame.scad`) used placeholder values. The table below records th
|
||||
|
||||
## Structural / Fabricated Parts
|
||||
|
||||
### Prototype Base Plate (`prototype_baseplate.scad`) — Rev B
|
||||
### Prototype Base Plate (`prototype_baseplate.scad`) — Rev C
|
||||
|
||||
> Batteries are removed from the base plate. Plate is now compact (680×130mm).
|
||||
> Stem socket replaces battery tray. See Part B (stem clamp) below.
|
||||
|
||||
| # | Part | Qty | Material | Cut size | Notes |
|
||||
|---|------|-----|----------|----------|-------|
|
||||
| 1 | Prototype base plate | 1 | 6mm 5052-H32 aluminium **or** 8mm clear acrylic | 680×220mm blank | Laser or CNC; export DXF from `RENDER="plate_2d"` |
|
||||
| 2 | Dropout clamp — lower (L+R) | 2 | 8mm 6061-T6 aluminium | 90×70mm blank each | Round bore Ø16.51mm; `RENDER="clamp_lower_2d"` |
|
||||
| 3 | Dropout clamp — upper (L+R) | 2 | 8mm 6061-T6 aluminium | 90×70mm blank each | D-cut bore (Ø16.25mm, 13.6mm flat chord); `RENDER="clamp_upper_2d"` |
|
||||
| 4 | FC standoff M3×6mm nylon | 4 | Nylon | — | MAMBA F722S vibration isolation |
|
||||
| 5 | Ø4mm alignment pin | 8 | Steel dowel | 16mm length | Clamp-to-plate alignment (2 per clamp stack) |
|
||||
| 1 | Base plate | 1 | 6mm 5052-H32 Al **or** 8mm acrylic | 680×130mm blank | `RENDER="plate_2d"` → DXF |
|
||||
| 2 | Dropout clamp — lower | 2 | 8mm 6061-T6 Al | 90×70mm blank | Round bore Ø16.51mm; `RENDER="clamp_lower_2d"` |
|
||||
| 3 | Dropout clamp — upper | 2 | 8mm 6061-T6 Al | 90×70mm blank | D-cut bore; `RENDER="clamp_upper_2d"` |
|
||||
| 4 | Stem flange ring | 2 | 6mm Al or acrylic | Ø82mm disc | One above + one below plate; `RENDER="stem_flange_2d"` |
|
||||
| 5 | Vertical stem tube | 1 | 38.1mm OD × 1.5mm wall 6061-T6 Al | 1050mm length | 1.5" EMT conduit is a drop-in alternative |
|
||||
| 6 | FC standoff M3×6mm nylon | 4 | Nylon | — | MAMBA F722S vibration isolation |
|
||||
| 7 | Ø4mm × 16mm alignment pin | 8 | Steel dowel | — | Dropout clamp-to-plate alignment |
|
||||
|
||||
### Battery Stem Clamp (`stem_battery_clamp.scad`) — Part B
|
||||
|
||||
| # | Part | Qty | Material | Notes |
|
||||
|---|------|-----|----------|-------|
|
||||
| 8 | Collar half | 2 | PETG FDM (5 perimeters, 40% infill) | Print flat-side-down; mirror 2nd in slicer. Bore Ø38.6mm |
|
||||
| 9 | Radial arm | 4 | 4mm 5052-H32 Al (laser-cut) **or** PETG FDM | `RENDER="arm_2d"` for DXF with `ARM_THICK=4`; or print at 8mm |
|
||||
| 10 | Battery cradle | 4 | PETG FDM (4 perimeters, 30% infill) | U-channel, open top; holds 1 pack per cradle |
|
||||
| 11 | M6×60 SHCS | 4 | SS | 2 collar clamping bolts × 2 sides |
|
||||
| 12 | M6 hex nut | 4 | SS | Captured in collar nut pockets |
|
||||
| 13 | M6×12 set screw | 2 | SS, cup-point | 1 per collar half for height lock |
|
||||
| 14 | M4×20 SHCS | 8 (16 for 4) | SS | Arm-to-collar bolts (2 per arm) |
|
||||
| 15 | M4×16 SHCS | 8 (16 for 4) | SS | Cradle-to-arm bolts (2 per cradle) |
|
||||
| 16 | M4 hex nut | 16 (32 for 4) | SS | Nuts for items 14 + 15 |
|
||||
| 17 | Velcro strap 25mm × 600mm | 4–8 | — | 1–2 per battery pack through cradle slots |
|
||||
|
||||
### Full Chassis (`chassis_frame.scad`) — Rev A (placeholder values — pending Rev B update)
|
||||
|
||||
@ -78,26 +98,27 @@ PR #7 (`chassis_frame.scad`) used placeholder values. The table below records th
|
||||
|
||||
---
|
||||
|
||||
## Battery
|
||||
## Battery (Vertical Stem Mount — Rev C)
|
||||
|
||||
> **Rev B update:** previous placeholder (185×72×52 mm) replaced with real pack dimensions.
|
||||
> Batteries mount VERTICALLY on the stem carousel, **not** on the base plate.
|
||||
> Each pack stands upright (420mm tall) in a cradle at the end of a radial arm.
|
||||
|
||||
| # | Part | Qty | Spec | Notes |
|
||||
|---|------|-----|------|-------|
|
||||
| 18 | Battery pack | 2 (default) | 24V, 420×88×56 mm each | Sit side-by-side on deck (2-pack = 420×176 mm footprint). Up to 4 packs with underdeck shelf. |
|
||||
| 19 | Velcro strap 25mm × 500mm | 4 | One per strap slot × 2 slots × 2 packs | Pass through 25mm plate slots at x=±105mm; cinch over pack |
|
||||
| 20 | BMS board | 1–2 | Matched to cell chemistry | Mount to deck underside near battery centre; one BMS can parallel both packs |
|
||||
| 21 | 4-pack underdeck shelf plate | 0 (option) | 6mm Al, 440×200mm | Required only for 4-pack config; attaches via M5 shelf bolts; carries 2 more packs below main deck |
|
||||
| 22 | M5×20 shelf bolt + nut | 8 | SS, for underdeck shelf | Only for 4-pack config; M5 holes in main plate are pre-punched when `BATT_PACKS=4` |
|
||||
| 18 | Battery pack | 2–4 | 24V, **420×88×56 mm** each (caliper-verified) | Snap into battery cradle from above |
|
||||
| 19 | BMS board | 1 | Matched to cell chemistry | Mount to stem or base plate underside; run wiring down stem |
|
||||
|
||||
### Battery footprint analysis
|
||||
### Battery stem clamp — configuration guide
|
||||
|
||||
| Config | Width (Y) | Length (X) | Fits on 600mm wheelbase? | Notes |
|
||||
|--------|-----------|-----------|--------------------------|-------|
|
||||
| 2-pack (default) | 176 mm | 420 mm | ✅ Yes | Centred between forks |
|
||||
| 4-pack (in-line) | 176 mm | 840 mm | ❌ No | 840 > 600 mm wheelbase |
|
||||
| 4-pack (side-by-side) | 352 mm | 420 mm | ❌ No | 352 > 210 mm plate depth |
|
||||
| 4-pack (2+2 underdeck) | 176 mm | 420 mm | ✅ Yes | 2 packs below main deck via shelf |
|
||||
| Config | Arm count | Carousel weight | Balance | Notes |
|
||||
|--------|-----------|-----------------|---------|-------|
|
||||
| 2-pack | 2 arms, 180° apart | ~1.4 kg | ✅ Symmetric | Minimum configuration |
|
||||
| 4-pack | 4 arms, 90° apart | ~2.8 kg | ✅ Symmetric | Maximum practical config |
|
||||
| 3-pack | 3 arms, 120° apart | ~2.1 kg | ⚠ Asymmetric mass | Needs counter-balance or avoid |
|
||||
|
||||
### CG height tuning
|
||||
|
||||
Slide entire carousel up/down the stem with M6 collar bolts loosened. Tighten at desired height. Typical balance point (initial estimate): batteries centred at 450–600 mm above base plate. Adjust in ≈50 mm increments during commissioning.
|
||||
|
||||
---
|
||||
|
||||
@ -112,18 +133,23 @@ PR #7 (`chassis_frame.scad`) used placeholder values. The table below records th
|
||||
|
||||
## Fasteners
|
||||
|
||||
| # | Part | Qty | Spec |
|
||||
|---|------|-----|------|
|
||||
| 23 | M5×16 SHCS | 24 | ISO 4762, SS |
|
||||
| 24 | M5 hex nut | 24 | ISO 4032, SS |
|
||||
| 25 | M4×12 SHCS | 12 | ISO 4762, SS |
|
||||
| 26 | M4 hex nut | 12 | ISO 4032, SS |
|
||||
| 27 | M3×10 SHCS | 20 | ISO 4762, SS |
|
||||
| 28 | M3 hex nut | 20 | ISO 4032, SS |
|
||||
| 29 | M3×6 BHCS | 8 | FC + Jetson board bolts |
|
||||
| 30 | M14×1.5 axle nut | 4 | One each side per motor, flanged | Confirm axle thread pitch on actual motors |
|
||||
| 31 | Serrated washer M14 | 4 | Axle anti-rotation |
|
||||
| 32 | Flat washer M5 | 48 | SS |
|
||||
| # | Part | Qty | Spec | Use |
|
||||
|---|------|-----|------|-----|
|
||||
| 20 | M5×16 SHCS | 16 | ISO 4762, SS | Dropout clamp bolts (4 per clamp × 4) |
|
||||
| 21 | M5×20 SHCS | 8 | ISO 4762, SS | Stem flange bolts (4 per flange × 2) |
|
||||
| 22 | M5 hex nut | 24 | ISO 4032, SS | |
|
||||
| 23 | M4×20 SHCS | 16 | ISO 4762, SS | Arm-to-collar (2 per arm × 4 arms × 2) |
|
||||
| 24 | M4×16 SHCS | 16 | ISO 4762, SS | Cradle-to-arm (2 per cradle × 4 arms × 2) |
|
||||
| 25 | M4 hex nut | 32 | ISO 4032, SS | |
|
||||
| 26 | M6×60 SHCS | 4 | ISO 4762, SS | Collar clamping bolts |
|
||||
| 27 | M6 hex nut | 4 | ISO 4032, SS | Captured in collar pockets |
|
||||
| 28 | M6×12 set screw | 2 | ISO 4026, SS cup-point | Stem height lock (1 per collar half) |
|
||||
| 29 | M3×10 SHCS | 12 | ISO 4762, SS | FC mount + miscellaneous |
|
||||
| 30 | M3×6 BHCS | 4 | ISO 4762, SS | FC board bolts |
|
||||
| 31 | Axle lock nut (match axle tip thread) | 4 | Flanged, confirm thread | 2 per motor |
|
||||
| 32 | Flat washer M5 | 32 | SS | |
|
||||
| 33 | Flat washer M4 | 32 | SS | |
|
||||
| 34 | Ø4×16 dowel pin | 8 | Steel | Dropout clamp alignment |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -1,126 +1,107 @@
|
||||
// =============================================================================
|
||||
// SaltyBot — Prototype Base Plate (Rev B — real battery dimensions)
|
||||
// SaltyBot — Prototype Base Plate (Rev C — compact, stem-mount)
|
||||
// Agent: sl-mechanical | 2026-02-28
|
||||
//
|
||||
// Laser-cut or CNC-routed flat plate (6mm aluminium or 8mm acrylic).
|
||||
// Uses CALIPER-VERIFIED hub motor axle measurements — replaces placeholder
|
||||
// values from chassis_frame.scad (PR #7).
|
||||
// Laser-cut or CNC-routed flat plate (6 mm Al / 8 mm acrylic).
|
||||
// Uses CALIPER-VERIFIED hub motor axle measurements (see PR #7 / #11).
|
||||
//
|
||||
// ── BATTERY LAYOUT (real measurements — NOT placeholder) ─────────────────────
|
||||
// Each pack: 420 mm (L) × 88 mm (W) × 56 mm (H)
|
||||
// 2-pack (default): side-by-side in Y → footprint 420 × 176 mm on deck
|
||||
// 4-pack (expansion): 2 more packs on secondary underdeck tray
|
||||
// (4-wide = 352 mm exceeds robot width; in-line = 840 mm exceeds wheelbase)
|
||||
// Plate depth: 210 mm (176 mm battery + 17 mm margin each side)
|
||||
// ARCHITECTURE CHANGE (Rev C):
|
||||
// Batteries are NO LONGER on the base plate.
|
||||
// They stand vertically on a central stem via stem_battery_clamp.scad.
|
||||
// The base plate is now compact — only axle dropouts + stem socket + FC mount.
|
||||
//
|
||||
// ── VERIFIED AXLE PROFILE (stepped D-cut) ────────────────────────────────────
|
||||
// Zone │ Feature │ Diameter / Width │ Length
|
||||
// ───────┼──────────────────┼────────────────────┼─────────
|
||||
// ── AXLE PROFILE (stepped D-cut, caliper-verified) ───────────────────────────
|
||||
// Zone │ Feature │ Ø / Width │ Length
|
||||
// ───────┼──────────────────┼────────────────────┼──────────
|
||||
// Base │ Round (near hub) │ Ø 16.11 mm │ 15.00 mm
|
||||
// D-cut │ Round OD │ Ø 15.95 mm │ 43.35 mm
|
||||
// │ Flat chord │ 13.00 mm across │
|
||||
// Tip │ Shoulder/end │ — │ 3.00 mm (tip lock nut seat)
|
||||
// │ Flat chord │ 13.00 mm │
|
||||
// Tip │ Shoulder/end │ — │ 3.00 mm
|
||||
// Total │ Hub face → tip │ — │ 65.50 mm
|
||||
// ───────┼──────────────────┼────────────────────┼─────────
|
||||
// Bearing seat collar OD: Ø 37.8 mm (hub centre)
|
||||
// Tire: 10 × 2.125" pneumatic (254 mm OD, 54 mm wide, 35 PSI)
|
||||
// Bearing seat collar: Ø 37.8 mm
|
||||
// Tire: 10 × 2.125" pneumatic (Ø 254 mm, 35 PSI)
|
||||
// =============================================================================
|
||||
|
||||
$fn = 128;
|
||||
|
||||
// =============================================================================
|
||||
// AXLE PARAMETERS — caliper-verified (edit only when re-measured)
|
||||
// AXLE PARAMETERS — caliper-verified
|
||||
// =============================================================================
|
||||
|
||||
AXLE_BASE_DIA = 16.11; // mm round section near hub face
|
||||
AXLE_BASE_LEN = 15.00; // mm length of base section
|
||||
AXLE_DCUT_DIA = 15.95; // mm round OD of D-cut zone
|
||||
AXLE_DCUT_FLAT = 13.00; // mm flat chord width (caliper across flat)
|
||||
AXLE_DCUT_LEN = 43.35; // mm D-cut section length
|
||||
AXLE_TIP_LEN = 3.00; // mm tip / shoulder
|
||||
AXLE_TOTAL = 65.50; // mm total protrusion from hub face
|
||||
BEARING_SEAT_OD = 37.80; // mm hub centre collar OD
|
||||
|
||||
TIRE_OD = 254.0; // mm 10" × 25.4
|
||||
TIRE_WIDTH = 54.0; // mm 2.125" × 25.4
|
||||
AXLE_CL_HEIGHT = TIRE_OD / 2; // 127 mm — axle centre above ground
|
||||
AXLE_BASE_DIA = 16.11;
|
||||
AXLE_BASE_LEN = 15.00;
|
||||
AXLE_DCUT_DIA = 15.95;
|
||||
AXLE_DCUT_FLAT = 13.00;
|
||||
AXLE_DCUT_LEN = 43.35;
|
||||
AXLE_TIP_LEN = 3.00;
|
||||
AXLE_TOTAL = 65.50;
|
||||
BEARING_SEAT_OD = 37.80;
|
||||
TIRE_OD = 254.0;
|
||||
AXLE_CL_HEIGHT = TIRE_OD / 2; // 127 mm above ground
|
||||
|
||||
// =============================================================================
|
||||
// PLATE PARAMETERS
|
||||
// =============================================================================
|
||||
|
||||
WHEELBASE = 600.0; // mm axle C/L to axle C/L
|
||||
// PLATE_DEPTH driven by 2-pack battery width: 2 × 88 mm = 176 mm + 2×15 mm edge = 206 mm min.
|
||||
// 210 mm gives ~17 mm edge margin each side; increase if structural ribs are added.
|
||||
PLATE_DEPTH = 210.0; // mm front-to-rear (was 220; reduced to match 2-pack footprint)
|
||||
PLATE_OVERHANG = 40.0; // mm plate extends past axle C/L on each side
|
||||
PLATE_THICK = 6.0; // mm stock thickness (6 mm Al / 8 mm acrylic)
|
||||
WHEELBASE = 600.0; // mm axle C/L to axle C/L
|
||||
// Plate depth now driven only by structural + FC needs (no battery footprint).
|
||||
PLATE_DEPTH = 130.0; // mm front-to-rear
|
||||
PLATE_OVERHANG = 40.0; // mm plate past axle C/L each side
|
||||
PLATE_THICK = 6.0; // mm
|
||||
|
||||
// Fork (open-ended slot in plate edge)
|
||||
// Width matched to base-section diameter + 0.4 mm running clearance
|
||||
FORK_W = AXLE_BASE_DIA + 0.4; // 16.51 mm
|
||||
FORK_DEPTH = 50.0; // mm slot depth inward from plate edge
|
||||
// Fork slot
|
||||
FORK_W = AXLE_BASE_DIA + 0.4; // 16.51 mm
|
||||
FORK_DEPTH = 50.0;
|
||||
|
||||
// Clamp block (two-piece sandwich, bolts through plate)
|
||||
CLAMP_L = 80.0; // mm along axle axis
|
||||
CLAMP_H = 60.0; // mm across axle (front-to-back of plate)
|
||||
CLAMP_THICK = 8.0; // mm each clamp layer — 8 mm Al or 10 mm acrylic
|
||||
CLAMP_BOLT_D = 5.3; // M5 clearance
|
||||
CLAMP_BOLT_DX = 22.0; // mm bolt ±X from axle C/L
|
||||
CLAMP_BOLT_DY = 22.0; // mm bolt ±Y from axle C/L (across plate)
|
||||
CLAMP_ALIGN_D = 4.1; // Ø4 alignment pin clearance
|
||||
// Dropout clamp (two-piece sandwich)
|
||||
CLAMP_L = 80.0;
|
||||
CLAMP_H = 60.0;
|
||||
CLAMP_THICK = 8.0;
|
||||
CLAMP_BOLT_D = 5.3; // M5
|
||||
CLAMP_BOLT_DX = 22.0;
|
||||
CLAMP_BOLT_DY = 22.0;
|
||||
CLAMP_ALIGN_D = 4.1; // Ø4 pin
|
||||
|
||||
// D-cut bore clearance (applied to both diameter and flat chord)
|
||||
DCUT_CL = 0.3; // mm all-round clearance on D-cut profile
|
||||
// D-cut bore clearance
|
||||
DCUT_CL = 0.3;
|
||||
|
||||
// FC mount — MAMBA F722S 30.5 × 30.5 mm M3 stack
|
||||
FC_PITCH = 30.5;
|
||||
FC_HOLE_D = 3.2;
|
||||
// FC mount — MAMBA F722S 30.5 × 30.5 mm M3
|
||||
FC_PITCH = 30.5;
|
||||
FC_HOLE_D = 3.2;
|
||||
// FC is offset toward front of plate (away from stem)
|
||||
FC_X_OFFSET = -40.0; // mm from plate centre (negative = front/motor side)
|
||||
|
||||
// Battery — REAL MEASUREMENTS (each cell pack)
|
||||
// ┌──────────────────────────────────────────────────────────────────────────┐
|
||||
// │ 420 mm (L) × 88 mm (W) × 56 mm (H) per pack │
|
||||
// │ Default config: 2 packs side-by-side → footprint 420 × 176 mm │
|
||||
// │ Expansion: 4 packs (2+2) → 4-pack requires underdeck shelf │
|
||||
// │ — 4-pack side-by-side (352 mm wide) exceeds robot width envelope │
|
||||
// │ — 4-pack in-line (840 mm long) exceeds wheelbase │
|
||||
// │ → Only viable 4-pack layout: 2 on deck + 2 on secondary underdeck tray │
|
||||
// └──────────────────────────────────────────────────────────────────────────┘
|
||||
BATT_L = 420.0; // mm pack length (runs along X / wheelbase axis)
|
||||
BATT_W = 88.0; // mm pack width (runs along Y / front-rear axis)
|
||||
BATT_H = 56.0; // mm pack height (clearance for under-deck routing)
|
||||
BATT_PACKS = 2; // packs on this plate (2 or 4); 4 adds shelf mounts
|
||||
BATT_INSET = 18.0; // mm mount-hole inset from each pack end
|
||||
BATT_STRAP_W = 25.0; // mm Velcro strap slot width
|
||||
BATT_STRAP_T = 4.0; // mm strap slot depth (through-slot in plate)
|
||||
// =============================================================================
|
||||
// STEM SOCKET PARAMETERS
|
||||
// =============================================================================
|
||||
|
||||
STEM_OD = 38.1; // mm 1.5" EMT conduit OD
|
||||
STEM_BORE = STEM_OD + 0.5; // 38.6 mm with clearance
|
||||
// Flange ring (laser-cut, bolts above + below plate to grip tube):
|
||||
STEM_FLANGE_OD = 82.0; // mm flange outer diameter
|
||||
STEM_FLANGE_BC = 66.0; // mm bolt circle diameter (4× M5 at 90°)
|
||||
STEM_FLANGE_T = 6.0; // mm = PLATE_THICK (flush-mount)
|
||||
// Stem position: at plate centre (X=0, Y=0)
|
||||
|
||||
// =============================================================================
|
||||
// UTILITIES
|
||||
// =============================================================================
|
||||
|
||||
// Utility
|
||||
M3 = 3.2; M4 = 4.3; M5 = 5.3;
|
||||
|
||||
// =============================================================================
|
||||
// COMPUTED GEOMETRY (do not edit directly)
|
||||
// =============================================================================
|
||||
|
||||
// D-cut bore geometry (with clearance):
|
||||
// r = (AXLE_DCUT_DIA + 2·DCUT_CL) / 2
|
||||
// fc = AXLE_DCUT_FLAT + 2·DCUT_CL (chord with clearance on each side)
|
||||
// d = distance from centre to flat = sqrt(r² – (fc/2)²)
|
||||
DCUT_R = (AXLE_DCUT_DIA + 2*DCUT_CL) / 2; // 8.275 mm
|
||||
DCUT_FC = AXLE_DCUT_FLAT + 2*DCUT_CL; // 13.60 mm
|
||||
// DCUT_D computed inside module (OpenSCAD has no sqrt at module-level constant)
|
||||
|
||||
// Plate outer bounds
|
||||
PLATE_X_HALF = WHEELBASE/2 + PLATE_OVERHANG; // ± 340 mm
|
||||
PLATE_X_HALF = WHEELBASE/2 + PLATE_OVERHANG; // ± 340 mm
|
||||
DCUT_R = (AXLE_DCUT_DIA + 2*DCUT_CL) / 2;
|
||||
DCUT_FC = AXLE_DCUT_FLAT + 2*DCUT_CL;
|
||||
|
||||
// =============================================================================
|
||||
// RENDER CONTROL
|
||||
// =============================================================================
|
||||
//
|
||||
// "assembly" full 3-D preview
|
||||
// "plate_2d" DXF — base plate
|
||||
// "clamp_lower_2d" DXF — lower dropout clamp (× 2)
|
||||
// "clamp_upper_2d" DXF — upper dropout clamp (× 2)
|
||||
// "stem_flange_2d" DXF — stem flange ring (× 2, one above + one below plate)
|
||||
|
||||
// Set RENDER to one of:
|
||||
// "assembly" full 3-D preview (default)
|
||||
// "plate_2d" 2-D projection of base plate (→ DXF)
|
||||
// "clamp_lower_2d" 2-D projection of lower clamp (→ DXF)
|
||||
// "clamp_upper_2d" 2-D projection of upper clamp (→ DXF)
|
||||
RENDER = "assembly";
|
||||
|
||||
if (RENDER == "assembly") {
|
||||
@ -131,6 +112,8 @@ if (RENDER == "assembly") {
|
||||
projection(cut=true) translate([0,0,-CLAMP_THICK/2]) clamp_lower();
|
||||
} else if (RENDER == "clamp_upper_2d") {
|
||||
projection(cut=true) translate([0,0,-CLAMP_THICK/2]) clamp_upper();
|
||||
} else if (RENDER == "stem_flange_2d") {
|
||||
projection(cut=true) translate([0,0,-STEM_FLANGE_T/2]) stem_flange();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@ -138,287 +121,228 @@ if (RENDER == "assembly") {
|
||||
// =============================================================================
|
||||
|
||||
module assembly() {
|
||||
color("Silver", 0.85) base_plate();
|
||||
color("Silver", 0.85) base_plate();
|
||||
|
||||
for (side = [-1, 1]) {
|
||||
// Lower clamp sits on top of base plate, below fork slot level
|
||||
color("SteelBlue", 0.8)
|
||||
color("SteelBlue", 0.80)
|
||||
translate([side * WHEELBASE/2, 0, PLATE_THICK])
|
||||
clamp_lower();
|
||||
|
||||
// Upper clamp stacks on top of lower clamp
|
||||
color("CornflowerBlue", 0.8)
|
||||
color("CornflowerBlue", 0.80)
|
||||
translate([side * WHEELBASE/2, 0, PLATE_THICK + CLAMP_THICK])
|
||||
clamp_upper();
|
||||
}
|
||||
|
||||
// Reference ghosts (not for export)
|
||||
%for (side = [-1, 1])
|
||||
color("Orange", 0.25)
|
||||
translate([side * WHEELBASE/2, 0, 0])
|
||||
rotate([0, side * 90, 0])
|
||||
axle_ghost();
|
||||
// Stem flange rings (above and below plate)
|
||||
color("DimGray", 0.70)
|
||||
translate([0, 0, -STEM_FLANGE_T])
|
||||
stem_flange();
|
||||
color("DimGray", 0.70)
|
||||
translate([0, 0, PLATE_THICK])
|
||||
stem_flange();
|
||||
|
||||
// Battery pack ghosts — shows 2-pack layout on deck surface
|
||||
%for (pack_y = [BATT_W/2, -BATT_W/2])
|
||||
color("DarkGoldenrod", 0.35)
|
||||
translate([-BATT_L/2, pack_y - BATT_W/2, PLATE_THICK])
|
||||
cube([BATT_L, BATT_W, BATT_H]);
|
||||
// Reference ghosts
|
||||
%color("Orange", 0.25)
|
||||
translate([0, 0, PLATE_THICK + STEM_FLANGE_T])
|
||||
cylinder(d=STEM_OD, h=800); // vertical stem
|
||||
%for (side = [-1, 1])
|
||||
color("Tomato", 0.2)
|
||||
translate([side * WHEELBASE/2, 0, 0])
|
||||
rotate([0, side*90, 0])
|
||||
axle_ghost();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BASE PLATE
|
||||
// BASE PLATE (Part A — compact)
|
||||
// =============================================================================
|
||||
|
||||
module base_plate() {
|
||||
R = 12; // corner radius
|
||||
difference() {
|
||||
// ── Outer profile (rounded corners via minkowski) ──────────────────
|
||||
R = 12; // corner radius
|
||||
// ── Outer profile ──
|
||||
linear_extrude(PLATE_THICK)
|
||||
minkowski() {
|
||||
square([2*(PLATE_X_HALF - R), PLATE_DEPTH - 2*R], center=true);
|
||||
circle(r=R);
|
||||
}
|
||||
|
||||
// ── Fork slots (open at ±X edges) ─────────────────────────────────
|
||||
// Slot is FORK_W wide, FORK_DEPTH deep, open at plate edge
|
||||
// ── Fork slots (open at ±X edges, semicircular tip) ──────────────
|
||||
for (side = [-1, 1]) {
|
||||
// Round the slot tip (half-circle end)
|
||||
union() {
|
||||
translate([side*(PLATE_X_HALF - FORK_DEPTH),
|
||||
-FORK_W/2, -1])
|
||||
cube([FORK_DEPTH + 1, FORK_W, PLATE_THICK + 2]);
|
||||
// Semicircular slot bottom
|
||||
translate([side*(PLATE_X_HALF - FORK_DEPTH), 0, -1])
|
||||
cylinder(d=FORK_W, h=PLATE_THICK + 2);
|
||||
}
|
||||
translate([side*(PLATE_X_HALF - FORK_DEPTH), -FORK_W/2, -1])
|
||||
cube([FORK_DEPTH + 1, FORK_W, PLATE_THICK + 2]);
|
||||
translate([side*(PLATE_X_HALF - FORK_DEPTH), 0, -1])
|
||||
cylinder(d=FORK_W, h=PLATE_THICK + 2);
|
||||
}
|
||||
|
||||
// ── Clamp bolt through-holes (4 per side × 2 sides) ────────────────
|
||||
// ── Bearing seat relief (prevents Ø37.8 mm collar binding on edge) ─
|
||||
for (side = [-1, 1])
|
||||
translate([side*PLATE_X_HALF - side*(BEARING_SEAT_OD/2 + 1),
|
||||
-BEARING_SEAT_OD/2, -1])
|
||||
cube([BEARING_SEAT_OD/2 + 2, BEARING_SEAT_OD, PLATE_THICK + 2]);
|
||||
|
||||
// ── Dropout clamp bolt through-holes ─────────────────────────────
|
||||
for (side = [-1, 1])
|
||||
for (dx = [-CLAMP_BOLT_DX, CLAMP_BOLT_DX])
|
||||
for (dy = [-CLAMP_BOLT_DY, CLAMP_BOLT_DY])
|
||||
translate([side * WHEELBASE/2 + dx, dy, -1])
|
||||
translate([side*WHEELBASE/2 + dx, dy, -1])
|
||||
cylinder(d=CLAMP_BOLT_D, h=PLATE_THICK + 2);
|
||||
|
||||
// ── Alignment pin holes (Ø4, 2 per clamp side) ─────────────────────
|
||||
// ── Alignment pin holes (Ø4) ──────────────────────────────────────
|
||||
for (side = [-1, 1])
|
||||
for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8])
|
||||
translate([side * WHEELBASE/2, dy, -1])
|
||||
translate([side*WHEELBASE/2, dy, -1])
|
||||
cylinder(d=CLAMP_ALIGN_D, h=PLATE_THICK + 2);
|
||||
|
||||
// ── FC mount holes (MAMBA F722S 30.5 × 30.5 M3) ────────────────────
|
||||
for (x = [-FC_PITCH/2, FC_PITCH/2])
|
||||
// ── Stem socket bore ──────────────────────────────────────────────
|
||||
translate([0, 0, -1])
|
||||
cylinder(d=STEM_BORE, h=PLATE_THICK + 2);
|
||||
|
||||
// ── Stem flange bolt holes (4× M5, 90° pattern on STEM_FLANGE_BC) ─
|
||||
for (a = [0, 90, 180, 270])
|
||||
rotate([0, 0, a])
|
||||
translate([STEM_FLANGE_BC/2, 0, -1])
|
||||
cylinder(d=M5, h=PLATE_THICK + 2);
|
||||
|
||||
// ── FC mount (MAMBA F722S 30.5 × 30.5 M3) ────────────────────────
|
||||
for (x = [FC_X_OFFSET - FC_PITCH/2, FC_X_OFFSET + FC_PITCH/2])
|
||||
for (y = [-FC_PITCH/2, FC_PITCH/2])
|
||||
translate([x, y, -1])
|
||||
cylinder(d=FC_HOLE_D, h=PLATE_THICK + 2);
|
||||
|
||||
// ── Battery mount holes ──────────────────────────────────────────────
|
||||
// Layout: 2 packs side-by-side, each running lengthwise (420 mm in X).
|
||||
// Pack centres at y = +BATT_W/2 (pack A, front)
|
||||
// y = -BATT_W/2 (pack B, rear)
|
||||
// 4 mount holes per pack (corners, BATT_INSET from each end) = 8 holes total.
|
||||
for (pack_y = [BATT_W/2, -BATT_W/2]) // two packs in Y
|
||||
for (dx = [-BATT_L/2 + BATT_INSET,
|
||||
BATT_L/2 - BATT_INSET]) // two holes in X per pack
|
||||
translate([dx, pack_y, -1])
|
||||
cylinder(d=M4, h=PLATE_THICK + 2);
|
||||
|
||||
// ── Velcro strap slots (2 slots per pack, run full Y depth) ─────────
|
||||
// Slots pierce the plate so the strap passes through from below.
|
||||
// Positioned at x = ±BATT_L/4 (quarter-length of battery).
|
||||
for (sx = [-BATT_L/4, BATT_L/4])
|
||||
translate([sx - BATT_STRAP_W/2, -PLATE_DEPTH/2 + 8, -1])
|
||||
cube([BATT_STRAP_W, PLATE_DEPTH - 16, PLATE_THICK + 2]);
|
||||
|
||||
// ── 4-pack expansion shelf attachment holes (M5, 4 per side) ────────
|
||||
// Only punched when BATT_PACKS >= 4.
|
||||
// These accept M5 bolts that hold a secondary underdeck tray for
|
||||
// two more packs (same 420×88mm dims) mounted below the main plate.
|
||||
if (BATT_PACKS >= 4)
|
||||
for (ex = [-BATT_L/2 - 10, -BATT_L/6,
|
||||
BATT_L/6, BATT_L/2 + 10])
|
||||
for (ey = [-PLATE_DEPTH/2 + 12, PLATE_DEPTH/2 - 12])
|
||||
translate([ex, ey, -1])
|
||||
cylinder(d=M5, h=PLATE_THICK + 2);
|
||||
|
||||
// ── Lightening / cable routing slots ────────────────────────────────
|
||||
// Placed between the two battery pack columns and at the centre.
|
||||
// Only if they don't overlap the strap slots (strap slots are at ±BATT_L/4).
|
||||
slot_w = 22;
|
||||
slot_h = BATT_W - 20; // runs between the pack boundaries
|
||||
for (x = [-BATT_L/3 + 10, 0, BATT_L/3 - 10])
|
||||
// ── Wiring / cable pass-through slots (2×, flanking stem) ─────────
|
||||
for (dy = [-30, 30])
|
||||
hull() {
|
||||
translate([x, -slot_h/2 + slot_w/2, -1])
|
||||
cylinder(d=slot_w, h=PLATE_THICK + 2);
|
||||
translate([x, slot_h/2 - slot_w/2, -1])
|
||||
cylinder(d=slot_w, h=PLATE_THICK + 2);
|
||||
translate([15, dy, -1]) cylinder(d=14, h=PLATE_THICK + 2);
|
||||
translate([-15, dy, -1]) cylinder(d=14, h=PLATE_THICK + 2);
|
||||
}
|
||||
|
||||
// ── Bearing seat relief (36mm slot lets hub collar clear plate edge) ─
|
||||
// Prevents Ø37.8mm bearing seat from binding against plate edge.
|
||||
for (side = [-1, 1])
|
||||
translate([side*PLATE_X_HALF - side*(BEARING_SEAT_OD/2 + 2),
|
||||
-BEARING_SEAT_OD/2, -1])
|
||||
cube([BEARING_SEAT_OD/2 + 3, BEARING_SEAT_OD, PLATE_THICK + 2]);
|
||||
// ── Lightening slots (between FC zone and dropout zones) ──────────
|
||||
for (sx = [-1, 1]) {
|
||||
// One slot each side of stem, in the structural corridor
|
||||
lx = sx * (WHEELBASE/4);
|
||||
hull() {
|
||||
translate([lx, -(PLATE_DEPTH/2 - 22), -1]) cylinder(d=18, h=PLATE_THICK+2);
|
||||
translate([lx, (PLATE_DEPTH/2 - 22), -1]) cylinder(d=18, h=PLATE_THICK+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// STEM FLANGE RING (laser-cut, qty 2 — one above, one below plate)
|
||||
// =============================================================================
|
||||
|
||||
module stem_flange() {
|
||||
difference() {
|
||||
cylinder(d=STEM_FLANGE_OD, h=STEM_FLANGE_T);
|
||||
// Stem bore (tight fit — tube presses into flange)
|
||||
translate([0, 0, -1])
|
||||
cylinder(d=STEM_BORE, h=STEM_FLANGE_T + 2);
|
||||
// 4× M5 flange bolts
|
||||
for (a = [0, 90, 180, 270])
|
||||
rotate([0, 0, a])
|
||||
translate([STEM_FLANGE_BC/2, 0, -1])
|
||||
cylinder(d=M5, h=STEM_FLANGE_T + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DROPOUT CLAMP — LOWER (round bore, base-section diameter)
|
||||
// =============================================================================
|
||||
// Sits directly on top of the base plate.
|
||||
// The 16.11 mm round bore captures the base axle section.
|
||||
// The fork slot in the base plate is reproduced here to allow the axle to
|
||||
// slide in from the side.
|
||||
|
||||
module clamp_lower() {
|
||||
difference() {
|
||||
// Body
|
||||
hull() {
|
||||
translate([-CLAMP_L/2 + CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK);
|
||||
translate([ CLAMP_L/2 - CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK);
|
||||
}
|
||||
|
||||
// Round bore — base axle diameter + clearance
|
||||
translate([0, 0, -1])
|
||||
cylinder(d = AXLE_BASE_DIA + 0.4, h = CLAMP_THICK + 2);
|
||||
|
||||
// Open entry slot (matches base plate fork slot — allows slide-in assembly)
|
||||
// Round bore (base zone)
|
||||
translate([0, 0, -1]) cylinder(d=AXLE_BASE_DIA + 0.4, h=CLAMP_THICK + 2);
|
||||
// Slide-in slot (open toward wheel side)
|
||||
translate([-CLAMP_L/2 - 1, -FORK_W/2, -1])
|
||||
cube([CLAMP_L/2 + 1, FORK_W, CLAMP_THICK + 2]);
|
||||
|
||||
// Clamp bolt holes
|
||||
// Clamp bolts
|
||||
for (dx = [-CLAMP_BOLT_DX, CLAMP_BOLT_DX])
|
||||
for (dy = [-CLAMP_BOLT_DY, CLAMP_BOLT_DY])
|
||||
translate([dx, dy, -1])
|
||||
cylinder(d=CLAMP_BOLT_D, h=CLAMP_THICK + 2);
|
||||
|
||||
// Alignment pin holes
|
||||
translate([dx, dy, -1]) cylinder(d=CLAMP_BOLT_D, h=CLAMP_THICK + 2);
|
||||
// Alignment pins
|
||||
for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8])
|
||||
translate([0, dy, -1])
|
||||
cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2);
|
||||
translate([0, dy, -1]) cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DROPOUT CLAMP — UPPER (D-cut bore, anti-rotation)
|
||||
// =============================================================================
|
||||
// Stacks on top of lower clamp.
|
||||
// D-cut bore matches the caliper-verified profile:
|
||||
// Ø 15.95 mm round OD, 13.00 mm flat chord
|
||||
// Clearance DCUT_CL applied all-round.
|
||||
// The flat is oriented toward +Y (front of robot) — rotate clamp at assembly
|
||||
// to match actual flat position on your axles.
|
||||
|
||||
module clamp_upper() {
|
||||
dcut_r = DCUT_R;
|
||||
dcut_fc = DCUT_FC;
|
||||
// Distance from bore CL to flat (chord geometry)
|
||||
dcut_d = sqrt(pow(dcut_r, 2) - pow(dcut_fc/2, 2));
|
||||
dcut_d = sqrt(pow(dcut_r, 2) - pow(DCUT_FC/2, 2));
|
||||
|
||||
difference() {
|
||||
// Body (same footprint as lower clamp)
|
||||
hull() {
|
||||
translate([-CLAMP_L/2 + CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK);
|
||||
translate([ CLAMP_L/2 - CLAMP_H/2, 0, 0]) cylinder(d=CLAMP_H, h=CLAMP_THICK);
|
||||
}
|
||||
|
||||
// D-cut bore:
|
||||
// 1. Full round circle of radius dcut_r
|
||||
// 2. Intersect with a box that removes the top (y > dcut_d)
|
||||
// Net result: D-shape with flat at +Y = dcut_d
|
||||
// D-cut bore
|
||||
translate([0, 0, -1])
|
||||
linear_extrude(CLAMP_THICK + 2)
|
||||
dcut_profile_2d(dcut_r, dcut_d);
|
||||
|
||||
// Open entry slot (same as lower clamp)
|
||||
// Slide-in slot
|
||||
translate([-CLAMP_L/2 - 1, -FORK_W/2, -1])
|
||||
cube([CLAMP_L/2 + 1, FORK_W, CLAMP_THICK + 2]);
|
||||
|
||||
// Clamp bolt holes
|
||||
// Clamp bolts
|
||||
for (dx = [-CLAMP_BOLT_DX, CLAMP_BOLT_DX])
|
||||
for (dy = [-CLAMP_BOLT_DY, CLAMP_BOLT_DY])
|
||||
translate([dx, dy, -1])
|
||||
cylinder(d=CLAMP_BOLT_D, h=CLAMP_THICK + 2);
|
||||
|
||||
// Alignment pin holes
|
||||
translate([dx, dy, -1]) cylinder(d=CLAMP_BOLT_D, h=CLAMP_THICK + 2);
|
||||
// Alignment pins
|
||||
for (dy = [-CLAMP_BOLT_DY + 8, CLAMP_BOLT_DY - 8])
|
||||
translate([0, dy, -1])
|
||||
cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2);
|
||||
|
||||
// Label emboss (orientation marker — "D-CUT" + flat side arrow)
|
||||
translate([-12, dcut_d + 1, CLAMP_THICK - 0.8])
|
||||
translate([0, dy, -1]) cylinder(d=CLAMP_ALIGN_D, h=CLAMP_THICK + 2);
|
||||
// Orientation emboss
|
||||
translate([0, dcut_d + 1.5, CLAMP_THICK - 0.8])
|
||||
linear_extrude(1)
|
||||
text("D", size=6, font="Liberation Sans:style=Bold", halign="center");
|
||||
// Arrow indicating flat direction
|
||||
translate([8, dcut_d - 1, CLAMP_THICK - 0.8])
|
||||
linear_extrude(1)
|
||||
polygon([[0,0],[4,-3],[4,3]]);
|
||||
polygon([[0,0],[-3,-5],[3,-5]]);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 2-D D-cut profile helper ──────────────────────────────────────────────────
|
||||
// r = bore radius (with clearance already applied)
|
||||
// flat_d = distance from bore CL to flat (computed from chord geometry)
|
||||
// ── D-cut 2D profile helper ───────────────────────────────────────────────────
|
||||
module dcut_profile_2d(r, flat_d) {
|
||||
intersection() {
|
||||
circle(r=r);
|
||||
// Keep everything from y = -(r+1) up to y = flat_d
|
||||
translate([-r - 1, -r - 1])
|
||||
square([2*(r + 1), r + 1 + flat_d]);
|
||||
square([2*(r+1), r + 1 + flat_d]);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// AXLE GHOST (for assembly visualisation)
|
||||
// AXLE GHOST (visualisation only)
|
||||
// =============================================================================
|
||||
|
||||
module axle_ghost() {
|
||||
// Bearing seat collar
|
||||
cylinder(d=BEARING_SEAT_OD, h=12);
|
||||
// Base zone — round
|
||||
translate([0, 0, 12])
|
||||
cylinder(d=AXLE_BASE_DIA, h=AXLE_BASE_LEN);
|
||||
// D-cut zone (approximate cylinder for ghost)
|
||||
translate([0, 0, 12 + AXLE_BASE_LEN])
|
||||
cylinder(d=AXLE_DCUT_DIA, h=AXLE_DCUT_LEN);
|
||||
// Tip
|
||||
translate([0, 0, 12 + AXLE_BASE_LEN + AXLE_DCUT_LEN])
|
||||
cylinder(d=10, h=AXLE_TIP_LEN);
|
||||
translate([0,0,12]) cylinder(d=AXLE_BASE_DIA, h=AXLE_BASE_LEN);
|
||||
translate([0,0,12+AXLE_BASE_LEN]) cylinder(d=AXLE_DCUT_DIA, h=AXLE_DCUT_LEN);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DXF / FLAT-PATTERN EXPORT GUIDE
|
||||
// DXF EXPORT
|
||||
// =============================================================================
|
||||
//
|
||||
// PART 1 — Base plate
|
||||
// openscad prototype_baseplate.scad \
|
||||
// -D 'RENDER="plate_2d"' \
|
||||
// -o baseplate_plate.dxf
|
||||
// Part 1 — Base plate:
|
||||
// openscad prototype_baseplate.scad -D 'RENDER="plate_2d"' -o baseplate.dxf
|
||||
//
|
||||
// PART 2 — Lower clamp (× 2, one per side)
|
||||
// openscad prototype_baseplate.scad \
|
||||
// -D 'RENDER="clamp_lower_2d"' \
|
||||
// -o baseplate_clamp_lower.dxf
|
||||
// Part 2 — Dropout clamp, lower (× 2):
|
||||
// openscad prototype_baseplate.scad -D 'RENDER="clamp_lower_2d"' -o clamp_lower.dxf
|
||||
//
|
||||
// PART 3 — Upper clamp (× 2, one per side)
|
||||
// openscad prototype_baseplate.scad \
|
||||
// -D 'RENDER="clamp_upper_2d"' \
|
||||
// -o baseplate_clamp_upper.dxf
|
||||
// Part 3 — Dropout clamp, upper (× 2):
|
||||
// openscad prototype_baseplate.scad -D 'RENDER="clamp_upper_2d"' -o clamp_upper.dxf
|
||||
//
|
||||
// MATERIAL NOTES
|
||||
// Base plate: 6 mm 5052-H32 aluminium (preferred)
|
||||
// 8 mm clear acrylic (quick prototype)
|
||||
// Clamp blocks: 8 mm 6061-T6 aluminium (preferred — tighter bore tolerance)
|
||||
// 10 mm PETG FDM (proto only — pre-drill bolt holes)
|
||||
// Part 4 — Stem flange ring (× 2, one each side of plate):
|
||||
// openscad prototype_baseplate.scad -D 'RENDER="stem_flange_2d"' -o stem_flange.dxf
|
||||
//
|
||||
// LASER PARAMETERS (6 mm Al, fibre laser)
|
||||
// Power: 3 kW | Speed: 1800 mm/min | Assist: N2
|
||||
// Min bore dia: 6 mm (M5 holes OK)
|
||||
//
|
||||
// DIMENSIONAL NOTES
|
||||
// Fork slot width (FORK_W): 16.51 mm — verify on actual axle before cut
|
||||
// D-cut flat clearance (DCUT_CL): 0.3 mm — adjust if axle spins in clamp
|
||||
// Bearing seat relief: check collar actually clears plate edge before tightening
|
||||
// Materials:
|
||||
// Plate + flanges : 6 mm 5052-H32 aluminium (preferred)
|
||||
// 8 mm clear acrylic (quick proto)
|
||||
// Dropout clamps : 8 mm 6061-T6 aluminium
|
||||
// Stem tube : 38.1 mm OD × 1.5 mm wall 6061-T6 (or 1.5" EMT)
|
||||
// Cut stem to ~1050 mm — allows batteries from ~100 mm to ~950 mm height.
|
||||
// =============================================================================
|
||||
|
||||
378
chassis/stem_battery_clamp.scad
Normal file
378
chassis/stem_battery_clamp.scad
Normal file
@ -0,0 +1,378 @@
|
||||
// =============================================================================
|
||||
// SaltyBot — Battery Stem Clamp (Part B)
|
||||
// Agent: sl-mechanical | 2026-02-28
|
||||
//
|
||||
// HEIGHT-ADJUSTABLE battery carousel that slides on the central vertical stem.
|
||||
// 2–4 battery packs stand UPRIGHT, arranged radially around the mast.
|
||||
//
|
||||
// HOW IT WORKS
|
||||
// 1. Two collar halves clamp around the stem at the desired height.
|
||||
// 2. Radial arms project outward from the collar (one per battery pack).
|
||||
// 3. Each arm tip has a battery cradle — an upward-open U-channel that
|
||||
// the pack slides into from above.
|
||||
// 4. Velcro straps thread through cradle slots and cinch around the pack.
|
||||
// 5. Loosen the M6 collar bolts → slide up/down for CG tuning.
|
||||
// Tighten → locks in place.
|
||||
//
|
||||
// BATTERY (each pack, standing vertically):
|
||||
// 420 mm tall × 88 mm wide × 56 mm deep (verified)
|
||||
//
|
||||
// ANGULAR LAYOUT
|
||||
// BATT_COUNT = 2 → arms at 90° and 270° (±Y, balanced front/rear)
|
||||
// BATT_COUNT = 4 → arms at 45°, 135°, 225°, 315° (each collar half owns 2)
|
||||
// BATT_COUNT = 3 → arms at 90°, 210°, 330°
|
||||
//
|
||||
// PARTS (set RENDER= to export each)
|
||||
// collar_half — 3D print × 2 (mirror pair, RENDER="collar_half")
|
||||
// arm — laser-cut or print × BATT_COUNT (RENDER="arm_2d" for DXF)
|
||||
// battery_cradle — 3D print × BATT_COUNT (RENDER="cradle")
|
||||
//
|
||||
// STEM
|
||||
// 38.1 mm OD × 1.5 mm wall 6061-T6 aluminium tube (or 1.5" EMT conduit).
|
||||
// Cut to ~1050 mm. Clamp can sit anywhere from 150 mm to 850 mm height.
|
||||
// =============================================================================
|
||||
|
||||
$fn = 64;
|
||||
|
||||
// =============================================================================
|
||||
// STEM
|
||||
// =============================================================================
|
||||
|
||||
STEM_OD = 38.1;
|
||||
STEM_BORE = STEM_OD + 0.5; // collar bore clearance
|
||||
|
||||
// =============================================================================
|
||||
// COLLAR
|
||||
// =============================================================================
|
||||
|
||||
COLLAR_H = 80.0; // mm taller = more grip / less slip risk
|
||||
COLLAR_OD = 84.0; // mm outer diameter (wall = (84−38.6)/2 ≈ 22.7 mm)
|
||||
|
||||
// Split plane: Y = 0 (each half is the +Y or −Y side)
|
||||
// Clamping bolts go through both halves at (±COLLAR_BOLT_X, 0, Z)
|
||||
COLLAR_BOLT_X = 24.0; // mm bolt ±X from stem axis
|
||||
COLLAR_BOLT_D = 6.5; // M6 clearance
|
||||
COLLAR_NUT_D = 11.0; // M6 hex nut AF + 0.5 mm tolerance (point-to-point ≈ 10.4, use 11)
|
||||
COLLAR_NUT_H = 5.2; // M6 standard nut height + 0.2 mm
|
||||
|
||||
// Height-lock / anti-rotation set screw (M6 thread on outer face of each half)
|
||||
SETSCREW_D = 6.1; // through-hole for M6 set screw
|
||||
|
||||
// Arm attachment pads on collar exterior (flat boss, one per arm)
|
||||
ARM_PAD_W = 32.0; // mm pad width (tangential)
|
||||
ARM_PAD_H = 18.0; // mm pad height
|
||||
ARM_PAD_T = 4.0; // mm pad protrusion from collar surface
|
||||
ARM_BOLT_D = 4.3; // M4 clearance (arm-to-collar bolt)
|
||||
ARM_BOLT_SPAN = 16.0; // mm C/L-to-C/L of two arm attachment bolts
|
||||
|
||||
// =============================================================================
|
||||
// ARMS & BATTERIES
|
||||
// =============================================================================
|
||||
|
||||
BATT_COUNT = 4; // 2, 3, or 4
|
||||
BATT_L = 420.0; // mm pack height (vertical)
|
||||
BATT_W = 88.0; // mm pack width (tangential)
|
||||
BATT_D = 56.0; // mm pack depth (radial, into stem)
|
||||
BATT_CL = 0.8; // mm all-round clearance in cradle
|
||||
|
||||
ARM_REACH = 55.0; // mm collar surface → battery near face
|
||||
ARM_W = 28.0; // mm arm width
|
||||
ARM_THICK = 8.0; // mm arm thickness (3D-print); 4 mm if laser-cut Al
|
||||
ARM_CRADLE_D = 4.3; // M4 clearance (cradle-to-arm bolt)
|
||||
|
||||
// =============================================================================
|
||||
// BATTERY CRADLE
|
||||
// =============================================================================
|
||||
|
||||
CRADLE_H = 80.0; // mm cradle height (pack extends BATT_L-CRADLE_H above)
|
||||
CRADLE_WALL = 4.5; // mm wall thickness
|
||||
CRADLE_STRAP_W = 25.0; // mm Velcro strap slot width
|
||||
CRADLE_STRAP_T = 6.0; // mm slot height
|
||||
|
||||
// =============================================================================
|
||||
// ANGULAR PLACEMENT
|
||||
// =============================================================================
|
||||
|
||||
// First arm angle chosen so all arms are clear of the Y=0 split plane
|
||||
ARM_START = (BATT_COUNT == 2) ? 90 :
|
||||
(BATT_COUNT == 4) ? 45 :
|
||||
/* 3 */ 90 ;
|
||||
|
||||
// Helper: is arm i on the +Y half (side=+1) or −Y half (side=−1)?
|
||||
// side = +1 → sin(angle) >= 0
|
||||
// side = -1 → sin(angle) < 0
|
||||
function arm_angle(i) = ARM_START + i * (360 / BATT_COUNT);
|
||||
function arm_on_side(i, side) =
|
||||
(side > 0) ? (sin(arm_angle(i)) >= -0.001) :
|
||||
(sin(arm_angle(i)) <= 0.001);
|
||||
|
||||
// =============================================================================
|
||||
// RENDER CONTROL
|
||||
// =============================================================================
|
||||
|
||||
// "assembly" — full 3-D preview with ghosts
|
||||
// "collar_half" — single collar half for printing (print 2, one mirrored)
|
||||
// "arm" — single arm for printing or laser-cut
|
||||
// "arm_2d" — 2-D DXF projection of arm
|
||||
// "cradle" — single battery cradle for printing
|
||||
|
||||
RENDER = "assembly";
|
||||
|
||||
if (RENDER == "assembly") {
|
||||
assembly();
|
||||
} else if (RENDER == "collar_half") {
|
||||
collar_half(side=1);
|
||||
} else if (RENDER == "arm") {
|
||||
arm();
|
||||
} else if (RENDER == "arm_2d") {
|
||||
projection(cut=true) translate([0, 0, -ARM_THICK/2]) arm();
|
||||
} else if (RENDER == "cradle") {
|
||||
battery_cradle();
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ASSEMBLY
|
||||
// =============================================================================
|
||||
|
||||
module assembly() {
|
||||
// Collar halves
|
||||
color("LightSlateGray", 0.88) collar_half(side= 1);
|
||||
color("SlateGray", 0.88) collar_half(side=-1);
|
||||
|
||||
// Arms + cradles at each battery position
|
||||
for (i = [0 : BATT_COUNT - 1]) {
|
||||
a = arm_angle(i);
|
||||
rotate([0, 0, a]) {
|
||||
// Arm: originates at collar surface, runs along +X
|
||||
color("DimGray", 0.90)
|
||||
translate([COLLAR_OD/2, 0, (COLLAR_H - ARM_THICK) / 2])
|
||||
arm();
|
||||
|
||||
// Cradle: at arm tip
|
||||
color("SteelBlue", 0.85)
|
||||
translate([COLLAR_OD/2 + ARM_REACH,
|
||||
-(BATT_W/2 + BATT_CL + CRADLE_WALL),
|
||||
(COLLAR_H - CRADLE_H) / 2])
|
||||
battery_cradle();
|
||||
|
||||
// Battery ghost (not for export)
|
||||
%color("DarkGoldenrod", 0.30)
|
||||
translate([COLLAR_OD/2 + ARM_REACH + CRADLE_WALL,
|
||||
-(BATT_W/2 + BATT_CL),
|
||||
(COLLAR_H - CRADLE_H) / 2])
|
||||
cube([BATT_D + 2*BATT_CL, BATT_W + 2*BATT_CL, BATT_L]);
|
||||
}
|
||||
}
|
||||
|
||||
// Stem ghost
|
||||
%color("Gray", 0.20)
|
||||
translate([0, 0, -(COLLAR_H * 2)])
|
||||
cylinder(d=STEM_OD, h=COLLAR_H * 14);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// COLLAR HALF
|
||||
// =============================================================================
|
||||
// Printed flat-side-down (split face = print bed).
|
||||
// Print TWO: one as-is (side=+1), one mirrored in slicer (side=−1).
|
||||
// They are identical; the mirror instruction handles orientation.
|
||||
//
|
||||
// Bolt pattern:
|
||||
// 4× M6 through the flat face (2 per half at ±COLLAR_BOLT_X)
|
||||
// M6 hex nut pockets on the flat face (captured before assembly)
|
||||
// 1× M6 set screw on the outer curved surface (height lock)
|
||||
//
|
||||
// Arm attachment:
|
||||
// Raised pad on outer curved surface at each arm angle for this half.
|
||||
// 2× M4 through-holes per pad; M4 hex nut pocket on inside of collar wall.
|
||||
|
||||
module collar_half(side = 1) {
|
||||
mid_z = COLLAR_H / 2;
|
||||
wall_t = (COLLAR_OD - STEM_BORE) / 2;
|
||||
// Half of collar: the Y≥0 half (side=+1) or Y≤0 half (side=−1)
|
||||
|
||||
difference() {
|
||||
union() {
|
||||
// ── Half-cylinder body ──────────────────────────────────────
|
||||
intersection() {
|
||||
cylinder(d=COLLAR_OD, h=COLLAR_H);
|
||||
// Keep only the appropriate half
|
||||
translate([-COLLAR_OD/2 - 1,
|
||||
(side > 0) ? 0 : -COLLAR_OD - 1,
|
||||
-1])
|
||||
cube([COLLAR_OD + 2, COLLAR_OD + 1, COLLAR_H + 2]);
|
||||
}
|
||||
|
||||
// ── Arm attachment pads ──────────────────────────────────────
|
||||
for (i = [0 : BATT_COUNT - 1]) {
|
||||
if (arm_on_side(i, side)) {
|
||||
a = arm_angle(i);
|
||||
rotate([0, 0, a])
|
||||
translate([COLLAR_OD/2, -ARM_PAD_W/2,
|
||||
mid_z - ARM_PAD_H/2])
|
||||
cube([ARM_PAD_T, ARM_PAD_W, ARM_PAD_H]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Stem bore ────────────────────────────────────────────────────
|
||||
translate([0, 0, -1])
|
||||
cylinder(d=STEM_BORE, h=COLLAR_H + 2);
|
||||
|
||||
// ── Clamping bolt holes (2× through flat split face) ─────────────
|
||||
// Bolt axis: along Y (perpendicular to split plane)
|
||||
// Holes at (±COLLAR_BOLT_X, 0, COLLAR_H/3) and (±COLLAR_BOLT_X, 0, 2*COLLAR_H/3)
|
||||
for (bx = [-COLLAR_BOLT_X, COLLAR_BOLT_X])
|
||||
for (bz = [COLLAR_H/3, 2*COLLAR_H/3])
|
||||
translate([bx, -1, bz])
|
||||
rotate([-90, 0, 0])
|
||||
cylinder(d=COLLAR_BOLT_D, h=COLLAR_OD/2 + 2);
|
||||
|
||||
// ── M6 nut pockets on outer flat face of each half ───────────────
|
||||
// Pocket depth = COLLAR_NUT_H from the far curved side inward.
|
||||
// This allows pre-installing the nuts before bolting the halves together.
|
||||
for (bx = [-COLLAR_BOLT_X, COLLAR_BOLT_X])
|
||||
for (bz = [COLLAR_H/3, 2*COLLAR_H/3])
|
||||
translate([bx, side * (COLLAR_OD/2 - COLLAR_NUT_H), bz])
|
||||
rotate([-90, 0, 0])
|
||||
cylinder(d=COLLAR_NUT_D, h=COLLAR_NUT_H + 1, $fn=6);
|
||||
|
||||
// ── Set screw hole (M6, on curved outer surface at mid-height) ────
|
||||
translate([0, side * (COLLAR_OD/2 + 1), COLLAR_H/2])
|
||||
rotate([90, 0, 0])
|
||||
cylinder(d=SETSCREW_D, h=COLLAR_OD/2 + 2);
|
||||
|
||||
// ── Arm bolt holes + nut pockets (through collar wall per arm) ────
|
||||
for (i = [0 : BATT_COUNT - 1]) {
|
||||
if (arm_on_side(i, side)) {
|
||||
a = arm_angle(i);
|
||||
for (dy = [-ARM_BOLT_SPAN/2, ARM_BOLT_SPAN/2])
|
||||
rotate([0, 0, a])
|
||||
translate([STEM_BORE/2 - 1, dy, mid_z])
|
||||
rotate([0, 90, 0]) {
|
||||
// Through-hole (M4 clearance all the way)
|
||||
cylinder(d=ARM_BOLT_D,
|
||||
h=COLLAR_OD/2 - STEM_BORE/2 + ARM_PAD_T + 2);
|
||||
// Nut pocket on bore interior face
|
||||
cylinder(d=10, h=4.5, $fn=6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ARM
|
||||
// =============================================================================
|
||||
// Flat bar, ARM_REACH × ARM_W × ARM_THICK.
|
||||
// Collar end: 2× M4 clearance holes at ±ARM_BOLT_SPAN/2 in Y.
|
||||
// Cradle end: 2× M4 clearance holes at ±(ARM_W/2 - 8) in Y.
|
||||
// Can be laser-cut from 4 mm Al plate (reduce ARM_THICK to 4 in RENDER="arm_2d").
|
||||
|
||||
module arm() {
|
||||
difference() {
|
||||
translate([0, -ARM_W/2, 0])
|
||||
cube([ARM_REACH, ARM_W, ARM_THICK]);
|
||||
|
||||
// Collar-end bolt holes (M4, match arm pad on collar)
|
||||
for (dy = [-ARM_BOLT_SPAN/2, ARM_BOLT_SPAN/2])
|
||||
translate([8, dy, -1])
|
||||
cylinder(d=ARM_BOLT_D, h=ARM_THICK + 2);
|
||||
|
||||
// Cradle-end bolt holes (M4)
|
||||
for (dy = [-(ARM_W/2 - 8), ARM_W/2 - 8])
|
||||
translate([ARM_REACH - 10, dy, -1])
|
||||
cylinder(d=ARM_CRADLE_D, h=ARM_THICK + 2);
|
||||
|
||||
// Lightening slot in centre (optional — reduces print material)
|
||||
if (ARM_REACH > 40) {
|
||||
slot_l = ARM_REACH - 34;
|
||||
slot_w = ARM_W - 16;
|
||||
translate([17, -slot_w/2, -1])
|
||||
hull() {
|
||||
translate([slot_w/2, slot_w/2, 0]) cylinder(d=slot_w/2*0.8, h=ARM_THICK+2);
|
||||
translate([slot_l - slot_w/2, slot_w/2, 0]) cylinder(d=slot_w/2*0.8, h=ARM_THICK+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// BATTERY CRADLE
|
||||
// =============================================================================
|
||||
// U-channel, open top for pack insertion from above.
|
||||
// Inner pocket: (BATT_D + 2*BATT_CL) radially × (BATT_W + 2*BATT_CL) tangentially.
|
||||
// Cradle height CRADLE_H — battery extends (BATT_L − CRADLE_H) above the cradle.
|
||||
//
|
||||
// Strap slots: 2× horizontal slots through front+rear walls (Velcro through-pass).
|
||||
// Base bolt holes: 2× M4 for arm attachment (arm bolts up through arm into cradle).
|
||||
|
||||
module battery_cradle() {
|
||||
cw = CRADLE_WALL;
|
||||
id = BATT_D + 2*BATT_CL; // inner depth (radial, +X direction)
|
||||
iw = BATT_W + 2*BATT_CL; // inner width (tangential, Y direction)
|
||||
|
||||
difference() {
|
||||
// Outer block
|
||||
cube([id + 2*cw, iw + 2*cw, CRADLE_H]);
|
||||
|
||||
// Battery slot (open top: subtract from cw to top + 1)
|
||||
translate([cw, cw, -1])
|
||||
cube([id, iw, CRADLE_H + 2]);
|
||||
|
||||
// Strap slots — through left and right walls (Y faces), 2 heights
|
||||
for (sz = [CRADLE_H * 0.30, CRADLE_H * 0.65])
|
||||
translate([-1, cw + (iw - CRADLE_STRAP_W) / 2, sz])
|
||||
cube([id + 2*cw + 2, CRADLE_STRAP_W, CRADLE_STRAP_T]);
|
||||
|
||||
// Arm attachment holes in floor (2× M4)
|
||||
for (dy = [cw + iw/2 - ARM_BOLT_SPAN/2,
|
||||
cw + iw/2 + ARM_BOLT_SPAN/2])
|
||||
translate([cw + id/2, dy, -1])
|
||||
cylinder(d=ARM_CRADLE_D, h=cw + 2);
|
||||
|
||||
// Corner chamfers (front face — aids pack insertion)
|
||||
chamfer_s = 5;
|
||||
for (cy = [cw - 0.01, cw + iw - chamfer_s + 0.01])
|
||||
translate([cw - 0.01, cy, CRADLE_H - chamfer_s])
|
||||
rotate([0, 45, 0])
|
||||
cube([chamfer_s * 1.42, chamfer_s, chamfer_s * 1.42]);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// DXF / PRINT EXPORT
|
||||
// =============================================================================
|
||||
//
|
||||
// COLLAR HALF (3D print × 2 — print one as-is, mirror second in slicer):
|
||||
// openscad stem_battery_clamp.scad -D 'RENDER="collar_half"' -o collar_half.stl
|
||||
// Print settings: PETG, 5 perimeters, 40% infill, 0.2 mm layer, no supports needed
|
||||
// (flat split face sits on bed; overhangs ≤ 45°)
|
||||
//
|
||||
// ARM — 3D print or laser-cut × BATT_COUNT:
|
||||
// Print: openscad stem_battery_clamp.scad -D 'RENDER="arm"' -o arm.stl
|
||||
// Laser (DXF): openscad stem_battery_clamp.scad \
|
||||
// -D 'RENDER="arm_2d"' -D 'ARM_THICK=4' -o arm.dxf
|
||||
// Laser material: 4 mm 5052-H32 aluminium
|
||||
//
|
||||
// BATTERY CRADLE (3D print × BATT_COUNT):
|
||||
// openscad stem_battery_clamp.scad -D 'RENDER="cradle"' -o cradle.stl
|
||||
// Print settings: PETG, 4 perimeters, 30% infill, 0.25 mm layer
|
||||
//
|
||||
// =============================================================================
|
||||
//
|
||||
// ASSEMBLY SEQUENCE
|
||||
// 1. Print collar halves × 2, cradles × BATT_COUNT.
|
||||
// 2. Laser-cut (or print) arms × BATT_COUNT.
|
||||
// 3. Press M4 hex nuts into collar bore-face pockets.
|
||||
// 4. Wrap collar halves around stem; thread M6 bolts through both halves.
|
||||
// Do not fully tighten yet — position to desired height.
|
||||
// 5. Bolt each arm to its collar pad (M4 × 20 SHCS from arm outward).
|
||||
// 6. Bolt each cradle to its arm tip (M4 × 16 SHCS from below).
|
||||
// 7. Drop battery packs into cradles from above; route Velcro straps.
|
||||
// 8. Tighten M6 collar bolts (≈ 6 N·m each). Use M6 set screw for rotation lock.
|
||||
//
|
||||
// CG TUNING
|
||||
// Loosen M6 collar bolts (do not fully remove). Slide entire carousel up/down.
|
||||
// Re-tighten. Typical balance point: batteries at 400–600 mm above base plate.
|
||||
// =============================================================================
|
||||
Loading…
x
Reference in New Issue
Block a user