Merge pull request 'feat: SaltyRover 4-wheel chassis (#73)' (#79) from sl-mechanical/rover-chassis into saltyrover-dev
This commit is contained in:
commit
0d4599e12e
228
chassis/rover_BOM.md
Normal file
228
chassis/rover_BOM.md
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
# SaltyRover Chassis — BOM + Assembly Notes
|
||||||
|
**Rev A — 2026-03-01 — sl-mechanical**
|
||||||
|
**Issue: #73**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
SaltyRover is the stable 4-wheel variant of SaltyLab.
|
||||||
|
Low CG, wide track — designed not to tip over.
|
||||||
|
Reuses the 25 mm vertical stem, sensor head, RPLIDAR, RealSense,
|
||||||
|
IMX219 camera mounts, and roll cage from SaltyLab without modification.
|
||||||
|
|
||||||
|
```
|
||||||
|
Top view (schematic):
|
||||||
|
|
||||||
|
Forward (+Y)
|
||||||
|
│
|
||||||
|
◉─────────────────────◉ ← front axle (AXLE_BASE/2 = 170 mm forward)
|
||||||
|
│ [Orin NX] │
|
||||||
|
│ [battery] │ ← flat packs below deck (low CG)
|
||||||
|
│ [battery] │
|
||||||
|
│ [FC] │
|
||||||
|
◉─────────────────────◉ ← rear axle
|
||||||
|
│
|
||||||
|
stem (centre)
|
||||||
|
|
||||||
|
Dimensions (approx):
|
||||||
|
Robot width (tyre-to-tyre): ~810 mm (TRACK_W=540 + 2×TIRE_W/2)
|
||||||
|
Robot length (axle-to-axle): ~340 mm (AXLE_BASE)
|
||||||
|
Deck width: 480 mm
|
||||||
|
Deck length: 500 mm
|
||||||
|
Ground clearance: ~50 mm (deck bottom to ground)
|
||||||
|
Overall height (with 550 mm stem + sensor head): ~800 mm
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Height Stack
|
||||||
|
|
||||||
|
```
|
||||||
|
Z from ground:
|
||||||
|
Z = 0 mm — ground
|
||||||
|
Z = 50 mm — chassis bottom (battery tray floor)
|
||||||
|
Z = 109 mm — deck bottom face
|
||||||
|
Z = 117 mm — deck top face (Z=0 in SCAD coords)
|
||||||
|
Z = 127 mm — motor axle CL (+10 mm above deck top)
|
||||||
|
Z = 139 mm — deck stem collar top (117+22)
|
||||||
|
Z = 145 mm — stem adapter flange top (139+6)
|
||||||
|
Z = 173 mm — stem clamp top (145+28)
|
||||||
|
Z = 723 mm — stem top with 550 mm rover stem
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Index
|
||||||
|
|
||||||
|
| File | Description | RENDER |
|
||||||
|
|------|-------------|--------|
|
||||||
|
| `saltyrover_chassis.scad` | Main deck plate, stem collar, standoffs | `assembly` / `deck` / `deck_2d` |
|
||||||
|
| `rover_motor_mount.scad` | L-bracket + axle clamp plate, 4× | `assembly` / `bracket` / `clamp_plate` / `bracket_2d` |
|
||||||
|
| `rover_battery_tray.scad` | Slide-out battery tray, 2–4 packs | `assembly` / `tray` / `rail` / `latch` / `tray_2d` |
|
||||||
|
| `rover_stem_adapter.scad` | Flange + split clamp, locks stem to deck | `assembly` / `base_flange` / `clamp_front` / `clamp_rear` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part A — Deck Plate (`saltyrover_chassis.scad`)
|
||||||
|
|
||||||
|
### Structural parts
|
||||||
|
|
||||||
|
| # | RENDER | Qty | Material | Process | Notes |
|
||||||
|
|---|--------|-----|----------|---------|-------|
|
||||||
|
| 1 | `deck_2d` | 1 | 8 mm 5052-H32 Al | Waterjet or CNC router | 480×500 mm blank |
|
||||||
|
| — | — | — | **or** 8 mm PETG FDM | Print in sections, bolted lap joints | Prototype only |
|
||||||
|
|
||||||
|
### Fasteners (deck to motor brackets)
|
||||||
|
|
||||||
|
| # | Spec | Qty | Use |
|
||||||
|
|---|------|-----|-----|
|
||||||
|
| 2 | M5×20 SHCS | 16 | Motor bracket flange to deck (4 per corner × 4) |
|
||||||
|
| 3 | M5 hex nut | 16 | Captured on deck underside |
|
||||||
|
| 4 | M4×16 SHCS | 4 | Stem adapter flange to deck collar |
|
||||||
|
| 5 | M4 flat washer | 4 | Under bolt head |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part B — Motor Brackets (`rover_motor_mount.scad`)
|
||||||
|
|
||||||
|
Print or CNC 4×. Each bracket handles one drive motor.
|
||||||
|
|
||||||
|
### Printed parts
|
||||||
|
|
||||||
|
| # | RENDER | Qty | Material | Settings | Notes |
|
||||||
|
|---|--------|-----|----------|----------|-------|
|
||||||
|
| 6 | `bracket` | 4 | PETG or PC | 5 perims, 60% infill | Print flange face down; add M5 inserts or use nuts |
|
||||||
|
| 7 | `clamp_plate` | 4 | PETG | 4 perims, 40% infill | Axle retention; print flat |
|
||||||
|
|
||||||
|
**CNC alternative:** `bracket_2d` → DXF, CNC route from 10 mm 6061-T6 Al plate.
|
||||||
|
|
||||||
|
### Fasteners
|
||||||
|
|
||||||
|
| # | Spec | Qty | Use |
|
||||||
|
|---|------|-----|-----|
|
||||||
|
| 8 | M4×20 SHCS | 8 | Axle clamp plate to bracket (2 per motor × 4) |
|
||||||
|
| 9 | M4 hex nut | 8 | Captured in bracket |
|
||||||
|
| 10 | Axle lock nut | 4 | Axle tip retention — **verify axle thread before ordering** (BOM.md: Ø≈10 mm tip) |
|
||||||
|
| 11 | M5×20 SHCS | 16 | Bracket flange to deck (from item 2 above) |
|
||||||
|
|
||||||
|
> ⚠ **Axle note:** BOM.md caliper values: base OD 16.11 mm, D-cut OD 15.95 mm, flat chord 13.00 mm.
|
||||||
|
> Verify AXLE_D / AXLE_FLAT / BEARING_OD in `rover_motor_mount.scad` before printing.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part C — Battery Tray (`rover_battery_tray.scad`)
|
||||||
|
|
||||||
|
### Printed parts
|
||||||
|
|
||||||
|
| # | RENDER | Qty | Material | Settings | Notes |
|
||||||
|
|---|--------|-----|----------|----------|-------|
|
||||||
|
| 12 | `tray` | 1 | PETG | 4 perims, 30% infill | Print open-top face up; no supports |
|
||||||
|
| 13 | `rail` | 2 | PETG | 5 perims, 40% infill | T-slot slide rail; print top-face down |
|
||||||
|
| 14 | `latch` | 1 | PETG or TPU 95A | 4 perims, 30% infill | Spring retention clip; TPU gives better snap feel |
|
||||||
|
|
||||||
|
### Fasteners
|
||||||
|
|
||||||
|
| # | Spec | Qty | Use |
|
||||||
|
|---|------|-----|-----|
|
||||||
|
| 15 | M4×12 FHCS | 6 | Slide rail to deck underside (3 per rail, countersunk) |
|
||||||
|
| 16 | M4 T-nut or nyloc | 6 | Captured under deck for rail bolts |
|
||||||
|
| 17 | M3×10 SHCS | 2 | Spring latch to tray end |
|
||||||
|
| 18 | Velcro strap 25 mm × 500 mm | 4–8 | Battery pack retention (1–2 per pack through tray floor slots) |
|
||||||
|
|
||||||
|
### Batteries
|
||||||
|
|
||||||
|
| # | Part | Qty | Spec |
|
||||||
|
|---|------|-----|------|
|
||||||
|
| 19 | Battery pack | 2–4 | 24 V, **420×88×56 mm** (BOM.md caliper-verified) |
|
||||||
|
| 20 | BMS board | 1 | Matched to cell chemistry; mount to deck underside near Y+ wall |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part D — Stem Adapter (`rover_stem_adapter.scad`)
|
||||||
|
|
||||||
|
| # | RENDER | Qty | Material | Settings | Notes |
|
||||||
|
|---|--------|-----|----------|----------|-------|
|
||||||
|
| 21 | `base_flange` | 1 | PETG | 5 perims, 40% infill | Print flat; add M4 brass inserts or use through-bolts |
|
||||||
|
| 22 | `clamp_front` | 1 | PETG | 5 perims, 40% infill | Flat-face down |
|
||||||
|
| 23 | `clamp_rear` | 1 | PETG | 5 perims, 40% infill | Mirror; flat-face down |
|
||||||
|
|
||||||
|
### Fasteners
|
||||||
|
|
||||||
|
| # | Spec | Qty | Use |
|
||||||
|
|---|------|-----|-----|
|
||||||
|
| 24 | M4×20 SHCS | 2 | Stem clamp clamping bolts |
|
||||||
|
| 25 | M4 hex nut | 2 | Captured in clamp rear half |
|
||||||
|
| 26 | M4×8 set screw | 1 | Rotation lock (front half) |
|
||||||
|
| 27 | M4×16 FHCS | 4 | Flange to deck collar (countersunk) |
|
||||||
|
|
||||||
|
### Stem tube
|
||||||
|
|
||||||
|
| # | Part | Qty | Spec | Notes |
|
||||||
|
|---|------|-----|------|-------|
|
||||||
|
| 28 | Vertical stem | 1 | 25 mm OD × 1.5 mm wall 6061-T6 Al, **550 mm length** | Cut from 1 m stock; SaltyLab uses 1000 mm |
|
||||||
|
|
||||||
|
> Sensor head, RPLIDAR, cameras, and roll cage from SaltyLab mount
|
||||||
|
> directly onto this 25 mm stem — no modifications required.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Motors
|
||||||
|
|
||||||
|
Same hoverboard hub motors as SaltyLab. **4× required for rover.**
|
||||||
|
|
||||||
|
| # | Part | Qty | Spec |
|
||||||
|
|---|------|-----|------|
|
||||||
|
| 29 | Hub motor | 4 | 10×2.125" tire, 36V nominal, ~350W; axle OD 16.11mm (caliper) |
|
||||||
|
| 30 | Motor cable extension | 4 | 6-pin JST-PH 300 mm hall sensor + 3-phase power |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mass Estimate
|
||||||
|
|
||||||
|
| Assembly | Est. mass |
|
||||||
|
|----------|-----------|
|
||||||
|
| Al deck plate | ~1.4 kg |
|
||||||
|
| Motor brackets × 4 (PETG) | ~0.5 kg |
|
||||||
|
| Hub motors × 4 | ~7.2 kg |
|
||||||
|
| Battery packs × 2 | ~1.4 kg |
|
||||||
|
| Battery tray (PETG) | ~0.3 kg |
|
||||||
|
| Stem + sensor head (from SaltyLab) | ~1.5 kg |
|
||||||
|
| Electronics (FC + Orin + wiring) | ~0.6 kg |
|
||||||
|
| Stem adapter + hardware | ~0.2 kg |
|
||||||
|
| Fasteners | ~0.3 kg |
|
||||||
|
| **Total estimate** | **~13.4 kg** |
|
||||||
|
|
||||||
|
> Wide 540 mm track + low 117 mm deck height → tip-over angle > 45°.
|
||||||
|
> CG is at approximately Z = 200 mm with packs flat and full payload.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Assembly Sequence
|
||||||
|
|
||||||
|
1. **Deck plate:** Cut or print `deck_2d`. Waterjet preferred for Al.
|
||||||
|
2. **Motor brackets:** Print (or CNC) 4× `bracket` + 4× `clamp_plate`.
|
||||||
|
- Test-fit axle D-cut bore before assembling to deck.
|
||||||
|
3. **Slide rails:** Print 2× `rail`. Bolt to deck underside.
|
||||||
|
4. **Stem adapter:** Print `base_flange` + `clamp_front` + `clamp_rear`.
|
||||||
|
- Insert stem through deck collar bore; seat flange on collar top.
|
||||||
|
- Bolt flange with 4× M4×16 FHCS.
|
||||||
|
- Slide clamp halves on stem above flange; tighten M4 clamping bolts (1.5 N·m).
|
||||||
|
- Tighten M4 set screw.
|
||||||
|
5. **Motor brackets:** Slide flange into deck edge slot; 4× M5×20 bolts.
|
||||||
|
- Do not torque until axle alignment is confirmed.
|
||||||
|
6. **Motors:** Drop axle into bracket dropout slot. Install clamp plate.
|
||||||
|
- Tighten clamp M4 bolts. Axle lock nut finger-tight + ¼ turn.
|
||||||
|
7. **Battery tray:** Slide tray in from +X with packs loaded.
|
||||||
|
- Latch snaps at full insertion.
|
||||||
|
8. **Sensor head + stem accessories:** Install from SaltyLab as-is.
|
||||||
|
- Recommend 550 mm stem for rover (sensor head at ~720 mm, stable).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tools Required
|
||||||
|
|
||||||
|
- M3/M4/M5 hex drivers
|
||||||
|
- Torque wrench: M5 structural bolts 4 N·m, M4 clamp bolts 1.5 N·m
|
||||||
|
- Thread locker (Loctite 243 blue) on axle lock nuts and stem clamp set screw
|
||||||
|
- Dial caliper — verify axle dimensions before bracket print/CNC
|
||||||
255
chassis/rover_battery_tray.scad
Normal file
255
chassis/rover_battery_tray.scad
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
// ============================================================
|
||||||
|
// rover_battery_tray.scad — SaltyRover Flat Battery Tray
|
||||||
|
// Rev A 2026-03-01 sl-mechanical
|
||||||
|
// ============================================================
|
||||||
|
// Slide-out tray for 2–4 × 420×88×56 mm battery packs
|
||||||
|
// laid FLAT below the rover deck plate.
|
||||||
|
//
|
||||||
|
// Packs orient with 420 mm left-right (X), 88 mm fore-aft
|
||||||
|
// per pack (Y), 56 mm tall (Z). BATT_N packs stack fore-aft.
|
||||||
|
//
|
||||||
|
// Tray slides out to the RIGHT (+X) for battery swap.
|
||||||
|
// Two slide rails (T-slot profile) run fore-aft inside
|
||||||
|
// the deck opening. Tray body rides on these rails.
|
||||||
|
// A spring-clip latch on the +X end retains the tray.
|
||||||
|
//
|
||||||
|
// Base plate attachment:
|
||||||
|
// Rail mounts bolt to deck underside (4× M4 per rail,
|
||||||
|
// counter-sunk flat-head).
|
||||||
|
//
|
||||||
|
// ⚠ VERIFY:
|
||||||
|
// BATT_PACK_L / W / H from caliper.
|
||||||
|
// RAIL_SLOT_W / H from your chosen extrusion or print.
|
||||||
|
//
|
||||||
|
// RENDER options:
|
||||||
|
// "assembly" tray + phantom packs (default)
|
||||||
|
// "tray" tray body for printing
|
||||||
|
// "rail" one T-slot slide rail (print 2×)
|
||||||
|
// "latch" spring latch for tray end (print 1×)
|
||||||
|
// "tray_2d" floor projection → DXF
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
RENDER = "assembly";
|
||||||
|
|
||||||
|
// ── Battery packs (BOM.md caliper-verified) ───────────────
|
||||||
|
BATT_PACK_L = 420.0; // left-right (X)
|
||||||
|
BATT_PACK_W = 88.0; // fore-aft per pack (Y)
|
||||||
|
BATT_PACK_H = 56.0; // height when flat (Z)
|
||||||
|
BATT_N = 2; // packs arranged fore-aft (2 or 4)
|
||||||
|
|
||||||
|
// ── Tray geometry ─────────────────────────────────────────
|
||||||
|
TRAY_WALL = 2.5; // wall thickness
|
||||||
|
TRAY_FLOOR = 3.0; // floor thickness
|
||||||
|
TRAY_PAD = 2.0; // per-side clearance inside tray (pack-to-wall)
|
||||||
|
|
||||||
|
// Inner cavity
|
||||||
|
TRAY_INN_W = BATT_PACK_L + 2*TRAY_PAD;
|
||||||
|
TRAY_INN_D = BATT_PACK_W * BATT_N + 2*TRAY_PAD;
|
||||||
|
TRAY_INN_H = BATT_PACK_H + TRAY_PAD; // open top
|
||||||
|
|
||||||
|
// Outer tray body
|
||||||
|
TRAY_OUT_W = TRAY_INN_W + 2*TRAY_WALL;
|
||||||
|
TRAY_OUT_D = TRAY_INN_D + 2*TRAY_WALL;
|
||||||
|
TRAY_OUT_H = TRAY_INN_H + TRAY_FLOOR;
|
||||||
|
|
||||||
|
// ── Slide rail ────────────────────────────────────────────
|
||||||
|
// T-profile rail runs fore-aft (Y), mounts to deck underside.
|
||||||
|
// Tray has matching T-slots on its side walls.
|
||||||
|
RAIL_L = TRAY_OUT_D + 40.0; // rail longer than tray for stop
|
||||||
|
RAIL_W = 14.0; // rail body width
|
||||||
|
RAIL_H = 8.0; // rail height below deck
|
||||||
|
RAIL_T_W = 10.0; // T-slot head width on tray side
|
||||||
|
RAIL_T_H = 4.0; // T-slot head height (captured in tray slot)
|
||||||
|
RAIL_CL = 0.3; // running clearance
|
||||||
|
RAIL_M4_SPC = 80.0; // M4 deck attachment bolt spacing along rail
|
||||||
|
|
||||||
|
// Tray T-slot channel (cut into tray outer wall)
|
||||||
|
SLOT_W = RAIL_T_W + 2*RAIL_CL;
|
||||||
|
SLOT_H = RAIL_T_H + RAIL_CL;
|
||||||
|
|
||||||
|
// Rail Y-spacing: rails at ±RAIL_Y from tray centre (fore-aft)
|
||||||
|
RAIL_Y_SPC = TRAY_INN_W - 20.0; // rails near X edges of tray
|
||||||
|
// Note: rails run in Y, so RAIL_Y_SPC is the X spread between them
|
||||||
|
|
||||||
|
// ── Strap slots ───────────────────────────────────────────
|
||||||
|
STRAP_W = 20.0; // Velcro strap width
|
||||||
|
STRAP_T = 3.0; // slot depth
|
||||||
|
|
||||||
|
// ── Latch ─────────────────────────────────────────────────
|
||||||
|
LATCH_L = 40.0; // latch body length
|
||||||
|
LATCH_W = 20.0;
|
||||||
|
LATCH_T = 4.0; // plate thickness
|
||||||
|
LATCH_FLEX = 25.0; // spring arm length
|
||||||
|
LATCH_TAB_H = 5.0; // retention tab height (hooks over deck edge)
|
||||||
|
LATCH_BOLT_D= 3.3; // M3 attachment bolt
|
||||||
|
|
||||||
|
// ── Fasteners ─────────────────────────────────────────────
|
||||||
|
M3_D = 3.2;
|
||||||
|
M4_D = 4.3;
|
||||||
|
M4_CS_D = 7.0; // flat-head countersink diam
|
||||||
|
|
||||||
|
$fn = 48;
|
||||||
|
e = 0.01;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// battery_tray()
|
||||||
|
// Z=0 at tray bottom face. Slides in +X direction.
|
||||||
|
// Inner cavity origin at (TRAY_WALL, TRAY_WALL, TRAY_FLOOR).
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module battery_tray() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// ── Outer tray body ────────────────────────
|
||||||
|
cube([TRAY_OUT_W, TRAY_OUT_D, TRAY_OUT_H]);
|
||||||
|
|
||||||
|
// ── Pull tab on +X face ────────────────────
|
||||||
|
translate([TRAY_OUT_W, TRAY_OUT_D/2 - 15, TRAY_FLOOR])
|
||||||
|
cube([18, 30, TRAY_OUT_H - TRAY_FLOOR]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Inner cavity (open top) ────────────────────
|
||||||
|
translate([TRAY_WALL, TRAY_WALL, TRAY_FLOOR])
|
||||||
|
cube([TRAY_INN_W, TRAY_INN_D, TRAY_INN_H + e]);
|
||||||
|
|
||||||
|
// ── Pack divider slot (for multi-pack separation) ──
|
||||||
|
if (BATT_N > 1)
|
||||||
|
for (pn = [1 : BATT_N - 1])
|
||||||
|
translate([TRAY_WALL - e,
|
||||||
|
TRAY_WALL + BATT_PACK_W * pn - 1,
|
||||||
|
TRAY_FLOOR])
|
||||||
|
cube([TRAY_INN_W + 2*e, 2, TRAY_INN_H + e]);
|
||||||
|
|
||||||
|
// ── Strap slots through floor (×2 per pack) ───
|
||||||
|
for (pn = [0 : BATT_N - 1])
|
||||||
|
for (sx = [TRAY_WALL + TRAY_INN_W*0.25,
|
||||||
|
TRAY_WALL + TRAY_INN_W*0.75])
|
||||||
|
translate([sx - STRAP_W/2,
|
||||||
|
TRAY_WALL + BATT_PACK_W * pn + 10,
|
||||||
|
-e])
|
||||||
|
cube([STRAP_W, BATT_PACK_W - 20, TRAY_FLOOR + 2*e]);
|
||||||
|
|
||||||
|
// ── T-slot channels on left (+Y) and right (-Y) faces ──
|
||||||
|
// Tray left wall: Y+ face — rail rides in from -X end
|
||||||
|
for (face_y=[TRAY_OUT_D - TRAY_WALL - e, -e]) {
|
||||||
|
translate([TRAY_OUT_W*0.2 - SLOT_W/2, face_y,
|
||||||
|
TRAY_FLOOR + TRAY_INN_H/2 - SLOT_H/2])
|
||||||
|
cube([TRAY_OUT_W*0.6, TRAY_WALL + 2*e, SLOT_H]);
|
||||||
|
// T-head channel
|
||||||
|
translate([TRAY_OUT_W*0.2 - RAIL_T_W/2 - RAIL_CL,
|
||||||
|
face_y,
|
||||||
|
TRAY_FLOOR + TRAY_INN_H/2 - SLOT_H/2 - RAIL_CL])
|
||||||
|
cube([RAIL_T_W + 2*RAIL_CL,
|
||||||
|
TRAY_WALL + 2*e,
|
||||||
|
SLOT_H + 2*RAIL_CL]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Ventilation / weight-save holes in floor (×4) ──
|
||||||
|
for (vx=[TRAY_OUT_W*0.25, TRAY_OUT_W*0.75])
|
||||||
|
for (vy=[TRAY_WALL + TRAY_INN_D*0.25,
|
||||||
|
TRAY_WALL + TRAY_INN_D*0.75])
|
||||||
|
translate([vx, vy, -e])
|
||||||
|
cylinder(d=25, h=TRAY_FLOOR + 2*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// slide_rail()
|
||||||
|
// Mounts to deck underside. Runs fore-aft (Y).
|
||||||
|
// T-head protrudes inward (X direction) into tray slot.
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module slide_rail() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// Rail body
|
||||||
|
translate([-RAIL_W/2, 0, 0])
|
||||||
|
cube([RAIL_W, RAIL_L, RAIL_H]);
|
||||||
|
// T-head flange (protrudes toward tray)
|
||||||
|
translate([-RAIL_T_W/2, 0, RAIL_H - RAIL_T_H])
|
||||||
|
cube([RAIL_T_W, RAIL_L, RAIL_T_H]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// M4 countersunk attachment holes to deck (×3 along rail)
|
||||||
|
for (ry = [15, RAIL_L/2, RAIL_L - 15])
|
||||||
|
translate([0, ry, RAIL_H + e])
|
||||||
|
rotate([180, 0, 0]) {
|
||||||
|
cylinder(d=M4_D, h=RAIL_H + 2*e);
|
||||||
|
cylinder(d1=M4_CS_D, d2=M4_D, h=3.5 + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rail end stop slot (tray cannot slide past rail end)
|
||||||
|
translate([-RAIL_W/2 - e, RAIL_L - 8, -e])
|
||||||
|
cube([RAIL_W + 2*e, 8 + e, RAIL_H - RAIL_T_H + e]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// spring_latch()
|
||||||
|
// Clips to tray +X end face. Spring arm hooks over
|
||||||
|
// deck opening edge to retain tray. Squeeze tab to release.
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module spring_latch() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// Base plate (bolts to tray end face)
|
||||||
|
cube([LATCH_W, LATCH_T, LATCH_L]);
|
||||||
|
// Spring arm
|
||||||
|
translate([LATCH_W/2 - 4, LATCH_T, LATCH_L - LATCH_FLEX])
|
||||||
|
cube([8, LATCH_T + LATCH_TAB_H, LATCH_FLEX + LATCH_TAB_H]);
|
||||||
|
// Retention tab
|
||||||
|
translate([LATCH_W/2 - 6, LATCH_T, LATCH_L - 2])
|
||||||
|
cube([12, LATCH_T + LATCH_TAB_H + 4, LATCH_TAB_H + 2]);
|
||||||
|
}
|
||||||
|
// M3 attachment holes (×2)
|
||||||
|
for (lz=[10, LATCH_L - 20])
|
||||||
|
translate([LATCH_W/2, -e, lz])
|
||||||
|
rotate([-90,0,0])
|
||||||
|
cylinder(d=LATCH_BOLT_D, h=LATCH_T + 2*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// Render selector
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
if (RENDER == "assembly") {
|
||||||
|
color("SteelBlue", 0.88) battery_tray();
|
||||||
|
|
||||||
|
// Phantom battery packs inside tray
|
||||||
|
for (pn = [0 : BATT_N - 1])
|
||||||
|
color("Gold", 0.35)
|
||||||
|
translate([TRAY_WALL + TRAY_PAD,
|
||||||
|
TRAY_WALL + TRAY_PAD + pn * BATT_PACK_W,
|
||||||
|
TRAY_FLOOR])
|
||||||
|
cube([BATT_PACK_L, BATT_PACK_W, BATT_PACK_H]);
|
||||||
|
|
||||||
|
// Slide rails
|
||||||
|
color("Silver", 0.80) {
|
||||||
|
translate([0, -20, TRAY_OUT_H])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
slide_rail();
|
||||||
|
translate([0, TRAY_OUT_D + 20 - RAIL_L, TRAY_OUT_H])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
slide_rail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Latch at +X end
|
||||||
|
color("OrangeRed", 0.85)
|
||||||
|
translate([TRAY_OUT_W + 18,
|
||||||
|
TRAY_OUT_D/2 - LATCH_W/2,
|
||||||
|
TRAY_OUT_H/2 - LATCH_L/2])
|
||||||
|
rotate([0, -90, 0])
|
||||||
|
spring_latch();
|
||||||
|
|
||||||
|
} else if (RENDER == "tray") {
|
||||||
|
battery_tray();
|
||||||
|
|
||||||
|
} else if (RENDER == "rail") {
|
||||||
|
slide_rail();
|
||||||
|
|
||||||
|
} else if (RENDER == "latch") {
|
||||||
|
spring_latch();
|
||||||
|
|
||||||
|
} else if (RENDER == "tray_2d") {
|
||||||
|
projection(cut=true)
|
||||||
|
translate([0, 0, -TRAY_FLOOR/2])
|
||||||
|
battery_tray();
|
||||||
|
}
|
||||||
240
chassis/rover_motor_mount.scad
Normal file
240
chassis/rover_motor_mount.scad
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
// ============================================================
|
||||||
|
// rover_motor_mount.scad — SaltyRover Drive Motor Brackets
|
||||||
|
// Rev A 2026-03-01 sl-mechanical
|
||||||
|
// ============================================================
|
||||||
|
// L-bracket that bolts to the deck edge and positions the drive
|
||||||
|
// motor axle at the correct height. Print or CNC 4×.
|
||||||
|
//
|
||||||
|
// Default values from BOM.md (caliper-verified hoverboard motor):
|
||||||
|
// Axle base OD: 16.11 mm
|
||||||
|
// D-cut OD: 15.95 mm (flat chord 13.00 mm)
|
||||||
|
// Bearing seat OD: 37.80 mm
|
||||||
|
// Axle CL above gnd: 127 mm
|
||||||
|
// Tire OD: 254 mm (10×2.125")
|
||||||
|
//
|
||||||
|
// Bracket geometry (all dims in mm):
|
||||||
|
// Vertical flange — bolts to deck edge (2× M5 SHCS)
|
||||||
|
// Horizontal arm — extends BRKT_REACH beyond deck edge
|
||||||
|
// to position axle CL at TRACK_W/2
|
||||||
|
// Axle channel — open-bottom dropout slot for easy
|
||||||
|
// motor install/removal; retained by
|
||||||
|
// a separate clamping plate (×1 per bracket)
|
||||||
|
// Bearing recess — 37.8 mm recess on inboard face
|
||||||
|
//
|
||||||
|
// ⚠ VERIFY before printing / CNC:
|
||||||
|
// AXLE_D, AXLE_FLAT, BEARING_OD from caliper measurement.
|
||||||
|
// DECK_BOT_H = GND_CLR + BATT_FLOOR_T + BATT_PACK_H.
|
||||||
|
// Adjust BRKT_REACH so TRACK_W matches chassis layout.
|
||||||
|
//
|
||||||
|
// Print orientation: flange face flat on bed.
|
||||||
|
// Material: PETG or PC, 5 perims, 60% infill.
|
||||||
|
// Alternative: CNC-routed 10mm 6061-T6 aluminium plate.
|
||||||
|
//
|
||||||
|
// RENDER options:
|
||||||
|
// "assembly" bracket + clamp plate + phantom motor axle
|
||||||
|
// "bracket" main L-bracket for printing/CNC
|
||||||
|
// "clamp_plate" axle retention clamp plate (print 4×)
|
||||||
|
// "bracket_2d" bracket floor projection → DXF
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
RENDER = "assembly";
|
||||||
|
|
||||||
|
// ── Axle / motor (BOM.md caliper-verified) ────────────────
|
||||||
|
AXLE_D = 16.11; // axle base section OD (round)
|
||||||
|
AXLE_FLAT = 13.00; // D-cut flat chord width
|
||||||
|
AXLE_D_DCUT = 15.95; // D-cut section OD
|
||||||
|
BEARING_OD = 37.80; // bearing seat collar OD
|
||||||
|
BEARING_D = BEARING_OD + 1.0; // bore clearance for bearing seat
|
||||||
|
BEARING_H = 8.0; // bearing recess depth on inboard face
|
||||||
|
|
||||||
|
AXLE_H = 127.0; // axle CL above ground
|
||||||
|
TIRE_OD = 254.0; // 10×2.125" tire outer diameter
|
||||||
|
|
||||||
|
// Dropout slot dims
|
||||||
|
DROP_W = AXLE_D + 2.0; // slot width (axle + 1 mm each side)
|
||||||
|
DROP_D = AXLE_H; // slot depth from bracket bottom (full height)
|
||||||
|
|
||||||
|
// ── Bracket geometry ─────────────────────────────────────
|
||||||
|
// Deck geometry (must match saltyrover_chassis.scad)
|
||||||
|
GND_CLR = 50.0;
|
||||||
|
BATT_FLOOR_T = 3.0;
|
||||||
|
BATT_PACK_H = 56.0;
|
||||||
|
DECK_T = 8.0;
|
||||||
|
DECK_BOT_H = GND_CLR + BATT_FLOOR_T + BATT_PACK_H; // 109 mm
|
||||||
|
DECK_TOP_H = DECK_BOT_H + DECK_T; // 117 mm
|
||||||
|
|
||||||
|
// Axle height relative to deck top:
|
||||||
|
AXLE_ABOVE_DECK = AXLE_H - DECK_TOP_H; // ~10 mm
|
||||||
|
|
||||||
|
// Bracket reach beyond deck edge to motor axle CL
|
||||||
|
BRKT_REACH = 40.0; // motor CL is BRKT_REACH mm outside deck edge
|
||||||
|
// (TRACK_W/2 - ROVER_W/2 = 270 - 240 = 30 mm +
|
||||||
|
// bearing housing clearance margin = 40 mm)
|
||||||
|
|
||||||
|
// Bracket plate dimensions
|
||||||
|
BRKT_T = 10.0; // bracket plate thickness
|
||||||
|
BRKT_H_ABOVE = AXLE_ABOVE_DECK + BEARING_OD/2 + 8.0; // above deck top
|
||||||
|
BRKT_H_BELOW = DECK_T + 12.0; // below deck bottom
|
||||||
|
BRKT_TOTAL_H = BRKT_H_ABOVE + BRKT_H_BELOW; // full height
|
||||||
|
|
||||||
|
// Width of bracket arm (fore-aft direction)
|
||||||
|
BRKT_W = 60.0; // covers motor fore-aft attachment bolts
|
||||||
|
|
||||||
|
// Flange for deck attachment
|
||||||
|
FLANGE_T = 8.0; // flange plate thickness
|
||||||
|
FLANGE_DEPTH = 20.0; // how deep flange sits on deck face (Y direction)
|
||||||
|
|
||||||
|
// M5 bolt holes: 2× through flange (deck attachment)
|
||||||
|
M5_D = 5.3;
|
||||||
|
MOT_BOLT_SPC = 30.0; // matches saltyrover_chassis.scad MOT_BOLT_SPC
|
||||||
|
|
||||||
|
// Clamping plate (retains axle in dropout slot)
|
||||||
|
CLAMP_T = 6.0; // clamp plate thickness
|
||||||
|
CLAMP_W = DROP_W + 12.0;
|
||||||
|
CLAMP_H = BEARING_D + 12.0;
|
||||||
|
CLAMP_BOLT_D= 4.3; // M4 clearance
|
||||||
|
CLAMP_BOLT_SPC = CLAMP_W - 10.0;
|
||||||
|
|
||||||
|
// Gusset (triangular fillet between flange and arm)
|
||||||
|
GUSSET_T = 8.0;
|
||||||
|
|
||||||
|
$fn = 64;
|
||||||
|
e = 0.01;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// motor_bracket()
|
||||||
|
// Main L-bracket. Coordinate: Z=0 at deck top.
|
||||||
|
// Bracket outboard face at X=0 (deck edge).
|
||||||
|
// Bracket arm extends +X toward motor.
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module motor_bracket() {
|
||||||
|
axle_z = AXLE_ABOVE_DECK; // axle CL in bracket coords
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// ── Vertical arm (extends +X from deck edge) ──
|
||||||
|
translate([0, -BRKT_W/2, -BRKT_H_BELOW])
|
||||||
|
cube([BRKT_REACH + BRKT_T, BRKT_W, BRKT_TOTAL_H]);
|
||||||
|
|
||||||
|
// ── Vertical flange (sits against deck edge, -X side) ──
|
||||||
|
translate([-FLANGE_DEPTH, -BRKT_W/2, -BRKT_H_BELOW])
|
||||||
|
cube([FLANGE_DEPTH, BRKT_W, BRKT_TOTAL_H]);
|
||||||
|
|
||||||
|
// ── Gusset (arm to flange transition) ──
|
||||||
|
translate([0, -BRKT_W/2, axle_z - GUSSET_T/2])
|
||||||
|
linear_extrude(GUSSET_T)
|
||||||
|
polygon([
|
||||||
|
[0, 0],
|
||||||
|
[BRKT_REACH/2, 0],
|
||||||
|
[0, BRKT_W]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Axle dropout slot (open at bottom, centered on arm tip) ──
|
||||||
|
translate([BRKT_REACH, -DROP_W/2, -BRKT_H_BELOW - e])
|
||||||
|
cube([BRKT_T + e, DROP_W, AXLE_H + 2*e]);
|
||||||
|
|
||||||
|
// ── Axle round bore at slot top ──
|
||||||
|
translate([BRKT_REACH, 0, axle_z])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=AXLE_D + 1.0, h=BRKT_T + 2*e);
|
||||||
|
|
||||||
|
// ── D-cut anti-rotation flat (matches axle flat chord) ──
|
||||||
|
translate([BRKT_REACH - e, -AXLE_FLAT/2, axle_z - AXLE_D/2 - e])
|
||||||
|
cube([BRKT_T + 2*e, AXLE_FLAT, AXLE_D/2 + e]);
|
||||||
|
|
||||||
|
// ── Bearing seat recess (inboard face, X=BRKT_T) ──
|
||||||
|
translate([BRKT_REACH + BRKT_T - BEARING_H, 0, axle_z])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=BEARING_D, h=BEARING_H + e);
|
||||||
|
|
||||||
|
// ── Clamping plate bolt holes (×2, retain axle) ──
|
||||||
|
for (dz=[-CLAMP_BOLT_SPC/2, CLAMP_BOLT_SPC/2])
|
||||||
|
translate([BRKT_REACH - e, 0, axle_z + dz])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=CLAMP_BOLT_D, h=BRKT_T + 2*e);
|
||||||
|
|
||||||
|
// ── Deck attachment holes through flange (M5 × 2) ──
|
||||||
|
for (bz=[-MOT_BOLT_SPC/2, MOT_BOLT_SPC/2])
|
||||||
|
translate([-FLANGE_DEPTH - e, 0, bz])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=M5_D, h=FLANGE_DEPTH + 2*e);
|
||||||
|
|
||||||
|
// ── Lightening pocket on arm (inboard face) ──
|
||||||
|
translate([BRKT_T, -BRKT_W/2 + 8, -BRKT_H_BELOW/2])
|
||||||
|
cube([BRKT_REACH - BRKT_T - 8,
|
||||||
|
BRKT_W - 16,
|
||||||
|
BRKT_H_BELOW/2 - 4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// axle_clamp_plate()
|
||||||
|
// Bolts to bracket outboard face to close dropout slot.
|
||||||
|
// Print flat face down. 1× per bracket.
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module axle_clamp_plate() {
|
||||||
|
axle_z = AXLE_ABOVE_DECK;
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
translate([-CLAMP_W/2, 0, axle_z - CLAMP_H/2])
|
||||||
|
cube([CLAMP_W, CLAMP_T, CLAMP_H]);
|
||||||
|
|
||||||
|
// Axle bore
|
||||||
|
translate([0, -e, axle_z])
|
||||||
|
rotate([-90, 0, 0])
|
||||||
|
cylinder(d=AXLE_D + 0.5, h=CLAMP_T + 2*e);
|
||||||
|
|
||||||
|
// Bearing seat relief
|
||||||
|
translate([0, CLAMP_T - BEARING_H + e, axle_z])
|
||||||
|
rotate([-90, 0, 0])
|
||||||
|
cylinder(d=BEARING_D, h=BEARING_H + e);
|
||||||
|
|
||||||
|
// M4 bolt holes (×2)
|
||||||
|
for (dz=[-CLAMP_BOLT_SPC/2, CLAMP_BOLT_SPC/2])
|
||||||
|
translate([0, -e, axle_z + dz])
|
||||||
|
rotate([-90, 0, 0])
|
||||||
|
cylinder(d=CLAMP_BOLT_D, h=CLAMP_T + 2*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// Render selector
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
if (RENDER == "assembly") {
|
||||||
|
color("DimGray", 0.90) motor_bracket();
|
||||||
|
color("SteelBlue", 0.85)
|
||||||
|
translate([BRKT_REACH + BRKT_T, 0, 0])
|
||||||
|
axle_clamp_plate();
|
||||||
|
|
||||||
|
// Phantom axle stub
|
||||||
|
color("Silver", 0.4)
|
||||||
|
translate([BRKT_REACH, 0, AXLE_ABOVE_DECK])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=AXLE_D, h=80);
|
||||||
|
|
||||||
|
// Phantom tire (semi-transparent outline)
|
||||||
|
color("Black", 0.12)
|
||||||
|
translate([BRKT_REACH + 40, 0, AXLE_ABOVE_DECK])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=TIRE_OD, h=54);
|
||||||
|
|
||||||
|
// Reference deck edge
|
||||||
|
color("Gold", 0.25)
|
||||||
|
translate([-FLANGE_DEPTH - 20, -BRKT_W/2, -BRKT_H_BELOW])
|
||||||
|
cube([20, BRKT_W, BRKT_TOTAL_H]);
|
||||||
|
|
||||||
|
} else if (RENDER == "bracket") {
|
||||||
|
motor_bracket();
|
||||||
|
|
||||||
|
} else if (RENDER == "clamp_plate") {
|
||||||
|
// Orient for printing: lay flat, rotate upright
|
||||||
|
translate([0, CLAMP_T, -AXLE_ABOVE_DECK])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
axle_clamp_plate();
|
||||||
|
|
||||||
|
} else if (RENDER == "bracket_2d") {
|
||||||
|
projection(cut=true)
|
||||||
|
translate([0, 0, -BRKT_H_BELOW - BRKT_T/2])
|
||||||
|
motor_bracket();
|
||||||
|
}
|
||||||
202
chassis/rover_stem_adapter.scad
Normal file
202
chassis/rover_stem_adapter.scad
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// ============================================================
|
||||||
|
// rover_stem_adapter.scad — SaltyRover Vertical Stem Adapter
|
||||||
|
// Rev A 2026-03-01 sl-mechanical
|
||||||
|
// ============================================================
|
||||||
|
// Secures the 25 mm OD vertical stem to the rover deck.
|
||||||
|
//
|
||||||
|
// Two-part system:
|
||||||
|
// base_flange() — annular flange plate bolts to deck top
|
||||||
|
// (4× M4 SHCS into deck; deck already has
|
||||||
|
// 25 mm stem bore through its centre collar)
|
||||||
|
// stem_clamp() — split collar clamps on stem above the
|
||||||
|
// deck collar; two M4 clamping bolts
|
||||||
|
// lock stem position / rotation
|
||||||
|
//
|
||||||
|
// Reuses the existing sensor head, RPLIDAR, camera mounts, and
|
||||||
|
// roll cage from SaltyLab — stem OD 25 mm is unchanged.
|
||||||
|
//
|
||||||
|
// Stem length options:
|
||||||
|
// SaltyLab 1000 mm (balance robot — tall for CG)
|
||||||
|
// SaltyRover 550 mm (rover — sensors visible, compact)
|
||||||
|
// The adapter is identical; only the purchased tube differs.
|
||||||
|
//
|
||||||
|
// ⚠ Ensure the deck stem collar (saltyrover_chassis.scad,
|
||||||
|
// STEM_COLLAR_OD=50 mm, H=22 mm) is the primary lateral
|
||||||
|
// support. The flange + clamp provide torque/axial lock.
|
||||||
|
//
|
||||||
|
// RENDER options:
|
||||||
|
// "assembly" flange + clamp + stem stub
|
||||||
|
// "base_flange" flange plate for printing
|
||||||
|
// "clamp_front" clamp front half for printing
|
||||||
|
// "clamp_rear" clamp rear half for printing
|
||||||
|
// "flange_2d" flange projection → DXF
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
RENDER = "assembly";
|
||||||
|
|
||||||
|
// ── Stem ─────────────────────────────────────────────────
|
||||||
|
STEM_OD = 25.0;
|
||||||
|
STEM_BORE = 25.4; // +0.4 clearance (same as sensor mounts)
|
||||||
|
STEM_L_ROVER = 550; // recommended rover stem length (mm)
|
||||||
|
|
||||||
|
// ── Base flange ───────────────────────────────────────────
|
||||||
|
// Sits on deck collar top. 4× M4 bolt through flange into deck.
|
||||||
|
FLANGE_OD = 80.0; // outer diameter
|
||||||
|
FLANGE_T = 6.0; // plate thickness
|
||||||
|
FLANGE_BOLT_BC = 65.0; // M4 bolt circle diameter
|
||||||
|
FLANGE_BOLT_D = 4.3; // M4 clearance
|
||||||
|
FLANGE_BOLT_N = 4; // number of bolts (at 90°)
|
||||||
|
// Deck collar height (must match saltyrover_chassis.scad STEM_COLLAR_H)
|
||||||
|
DECK_COLLAR_H = 22.0;
|
||||||
|
|
||||||
|
// ── Split stem clamp ─────────────────────────────────────
|
||||||
|
// Sits on top of flange; clamped M4 bolts lock stem.
|
||||||
|
COL_OD = 52.0; // clamp outer diameter
|
||||||
|
COL_H = 28.0; // clamp height (above flange)
|
||||||
|
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 across-flats
|
||||||
|
COL_NUT_H = 3.4; // hex nut height
|
||||||
|
|
||||||
|
// Set screw for rotation lock (front half)
|
||||||
|
SET_SCREW_D = 4.5; // M4 set screw
|
||||||
|
|
||||||
|
// ── Fasteners ─────────────────────────────────────────────
|
||||||
|
M4_D = 4.3;
|
||||||
|
|
||||||
|
$fn = 64;
|
||||||
|
e = 0.01;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// base_flange()
|
||||||
|
// Sits on top of the deck stem collar.
|
||||||
|
// Z=0 at deck top (collar rises from here).
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module base_flange() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// Annular flange plate (sits on collar top)
|
||||||
|
translate([0, 0, DECK_COLLAR_H])
|
||||||
|
cylinder(d=FLANGE_OD, h=FLANGE_T);
|
||||||
|
// Short skirt that drops inside/over collar
|
||||||
|
translate([0, 0, DECK_COLLAR_H - 4])
|
||||||
|
cylinder(d=FLANGE_OD - 8, h=4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stem bore
|
||||||
|
translate([0, 0, DECK_COLLAR_H - 4 - e])
|
||||||
|
cylinder(d=STEM_BORE, h=FLANGE_T + 4 + 2*e);
|
||||||
|
|
||||||
|
// M4 bolts through flange + down into deck (×4)
|
||||||
|
for (ang=[0, 90, 180, 270])
|
||||||
|
rotate([0, 0, ang])
|
||||||
|
translate([FLANGE_BOLT_BC/2, 0, DECK_COLLAR_H - e])
|
||||||
|
cylinder(d=FLANGE_BOLT_D, h=FLANGE_T + 2*e);
|
||||||
|
|
||||||
|
// Countersink on top face
|
||||||
|
for (ang=[0, 90, 180, 270])
|
||||||
|
rotate([0, 0, ang])
|
||||||
|
translate([FLANGE_BOLT_BC/2, 0, DECK_COLLAR_H + FLANGE_T - 3.5])
|
||||||
|
cylinder(d1=FLANGE_BOLT_D, d2=8.5, h=3.5 + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// stem_clamp_half(side)
|
||||||
|
// Split collar clamps on stem above the flange.
|
||||||
|
// Print flat-face-down. side = "front" | "rear"
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module stem_clamp_half(side="front") {
|
||||||
|
y_front = (side == "front");
|
||||||
|
|
||||||
|
// Clamp Z origin: on top of flange
|
||||||
|
clamp_z0 = DECK_COLLAR_H + FLANGE_T;
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
// D-shaped half
|
||||||
|
intersection() {
|
||||||
|
translate([0, 0, clamp_z0])
|
||||||
|
cylinder(d=COL_OD, h=COL_H);
|
||||||
|
translate([-COL_OD/2,
|
||||||
|
y_front ? 0 : -COL_OD/2,
|
||||||
|
clamp_z0])
|
||||||
|
cube([COL_OD, COL_OD/2, COL_H]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stem bore
|
||||||
|
translate([0, 0, clamp_z0 - e])
|
||||||
|
cylinder(d=STEM_BORE, h=COL_H + 2*e);
|
||||||
|
|
||||||
|
// M4 clamping bolt holes (Y direction, through front half)
|
||||||
|
for (bx=[-COL_BOLT_X, COL_BOLT_X])
|
||||||
|
translate([bx,
|
||||||
|
y_front ? COL_OD/2 : 0,
|
||||||
|
clamp_z0 + COL_H/2])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=COL_BOLT_D, h=COL_OD/2 + e);
|
||||||
|
|
||||||
|
// M4 hex nut pockets in rear half
|
||||||
|
if (!y_front)
|
||||||
|
for (bx=[-COL_BOLT_X, COL_BOLT_X])
|
||||||
|
translate([bx,
|
||||||
|
-(COL_OD/4 + e),
|
||||||
|
clamp_z0 + COL_H/2])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=COL_NUT_W/cos(30),
|
||||||
|
h=COL_NUT_H + e, $fn=6);
|
||||||
|
|
||||||
|
// M4 set screw hole (front half, mid-height, horizontal)
|
||||||
|
if (y_front)
|
||||||
|
translate([0, COL_OD/2,
|
||||||
|
clamp_z0 + COL_H * 0.65])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=SET_SCREW_D,
|
||||||
|
h=COL_OD/2 - STEM_BORE/2 + e);
|
||||||
|
|
||||||
|
// Mating face chamfer (0.2 mm, prevents elephant-foot binding)
|
||||||
|
translate([0, 0, clamp_z0 - e])
|
||||||
|
rotate([0, 0, y_front ? 0 : 180])
|
||||||
|
translate([-COL_OD/2, -0.2, 0])
|
||||||
|
cube([COL_OD, 0.2, COL_H + 2*e]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// Render selector
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
if (RENDER == "assembly") {
|
||||||
|
// Phantom deck collar reference
|
||||||
|
color("Gray", 0.15)
|
||||||
|
difference() {
|
||||||
|
cylinder(d=50, h=DECK_COLLAR_H);
|
||||||
|
translate([0,0,-e]) cylinder(d=STEM_BORE, h=DECK_COLLAR_H+2*e);
|
||||||
|
}
|
||||||
|
|
||||||
|
color("SteelBlue", 0.90) base_flange();
|
||||||
|
color("CornflowerBlue", 0.90) stem_clamp_half("front");
|
||||||
|
color("SlateBlue", 0.90)
|
||||||
|
mirror([0,1,0]) stem_clamp_half("rear");
|
||||||
|
|
||||||
|
// Phantom stem stub
|
||||||
|
color("Silver", 0.30)
|
||||||
|
translate([0, 0, DECK_COLLAR_H + FLANGE_T + COL_H])
|
||||||
|
cylinder(d=STEM_OD, h=STEM_L_ROVER);
|
||||||
|
|
||||||
|
} else if (RENDER == "base_flange") {
|
||||||
|
// Print flat; rotate flange down
|
||||||
|
translate([0, 0, -(DECK_COLLAR_H - 4)])
|
||||||
|
base_flange();
|
||||||
|
|
||||||
|
} else if (RENDER == "clamp_front") {
|
||||||
|
translate([0, 0, -(DECK_COLLAR_H + FLANGE_T)])
|
||||||
|
stem_clamp_half("front");
|
||||||
|
|
||||||
|
} else if (RENDER == "clamp_rear") {
|
||||||
|
translate([0, 0, -(DECK_COLLAR_H + FLANGE_T)])
|
||||||
|
stem_clamp_half("rear");
|
||||||
|
|
||||||
|
} else if (RENDER == "flange_2d") {
|
||||||
|
projection(cut=true)
|
||||||
|
translate([0, 0, -(DECK_COLLAR_H + FLANGE_T/2)])
|
||||||
|
base_flange();
|
||||||
|
}
|
||||||
218
chassis/saltyrover_chassis.scad
Normal file
218
chassis/saltyrover_chassis.scad
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
// ============================================================
|
||||||
|
// saltyrover_chassis.scad — SaltyRover 4-Wheel Base Plate
|
||||||
|
// Rev A 2026-03-01 sl-mechanical
|
||||||
|
// ============================================================
|
||||||
|
// Parametric deck plate for the stable 4-wheel SaltyRover.
|
||||||
|
// Low/wide/stable design — reuses sensor head + 25 mm stem.
|
||||||
|
//
|
||||||
|
// Coordinate convention:
|
||||||
|
// Z = 0 deck top face
|
||||||
|
// +Y forward
|
||||||
|
// +X right (motor side)
|
||||||
|
//
|
||||||
|
// Battery orientation:
|
||||||
|
// Packs laid FLAT (56 mm tall, 420 mm running left-right,
|
||||||
|
// 88 mm per pack fore-aft). N packs arranged fore-aft.
|
||||||
|
// 2-pack tray: 430 × 186 mm opening.
|
||||||
|
// 4-pack tray: 430 × 362 mm opening.
|
||||||
|
//
|
||||||
|
// Motor positions are at ±TRACK_W/2 (X), ±AXLE_BASE/2 (Y).
|
||||||
|
// Motor brackets (rover_motor_mount.scad) bolt to deck edge
|
||||||
|
// and extend BRKT_REACH mm outward to hold axle at AXLE_H.
|
||||||
|
//
|
||||||
|
// RENDER options:
|
||||||
|
// "assembly" full deck + phantom batteries + stem stub
|
||||||
|
// "deck" deck plate only (review)
|
||||||
|
// "deck_2d" floor projection → DXF for waterjet/CNC
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
RENDER = "assembly";
|
||||||
|
|
||||||
|
// ── Deck footprint ────────────────────────────────────────
|
||||||
|
ROVER_L = 500.0; // fore-aft (Y)
|
||||||
|
ROVER_W = 480.0; // left-right (X) — sized around battery width
|
||||||
|
DECK_T = 8.0; // deck thickness
|
||||||
|
DECK_R = 15.0; // corner fillet radius
|
||||||
|
|
||||||
|
// ── Drive geometry (caliper-verified motor data from BOM.md) ──
|
||||||
|
TRACK_W = 540.0; // motor axle CL to CL, left-right
|
||||||
|
AXLE_BASE = 340.0; // motor axle CL to CL, fore-aft
|
||||||
|
AXLE_H = 127.0; // axle CL above ground (10×2.125" wheel, caliper)
|
||||||
|
GND_CLR = 50.0; // minimum chassis ground clearance
|
||||||
|
|
||||||
|
// Height of deck bottom above ground:
|
||||||
|
// GND_CLR + battery_tray_floor + battery_height
|
||||||
|
BATT_FLOOR_T = 3.0;
|
||||||
|
BATT_PACK_H = 56.0; // flat-laid pack height
|
||||||
|
DECK_BOT_H = GND_CLR + BATT_FLOOR_T + BATT_PACK_H; // 109 mm
|
||||||
|
// Axle above deck top = AXLE_H - (DECK_BOT_H + DECK_T) ≈ +10 mm
|
||||||
|
|
||||||
|
// ── Battery packs (BOM.md caliper-verified: 420×88×56 mm) ──
|
||||||
|
// Laid flat, 420 mm running left-right (X), 88 mm per pack (Y),
|
||||||
|
// 56 mm tall (Z). BATT_N packs arranged side-by-side fore-aft.
|
||||||
|
BATT_X_DIM = 420.0;
|
||||||
|
BATT_Y_DIM = 88.0; // per-pack fore-aft depth
|
||||||
|
BATT_N = 2; // packs fore-aft (2 = 176 mm; 4 = 352 mm)
|
||||||
|
TRAY_MARGIN = 5.0; // extra margin on each side of tray opening
|
||||||
|
|
||||||
|
// ── Stem socket (deck centre) ─────────────────────────────
|
||||||
|
STEM_BORE = 25.5; // 25 mm tube + 0.5 clearance
|
||||||
|
STEM_COLLAR_OD = 50.0;
|
||||||
|
STEM_COLLAR_H = 22.0; // raised boss height above deck top
|
||||||
|
|
||||||
|
// ── FC mount (MAMBA F722S, 30.5×30.5 M3) ─────────────────
|
||||||
|
FC_SPACING = 30.5;
|
||||||
|
FC_HOLE_D = 3.2;
|
||||||
|
FC_STANDOFF_H= 6.0;
|
||||||
|
// FC centred forward of battery tray
|
||||||
|
FC_X = 0.0;
|
||||||
|
FC_Y = ROVER_L/2 - 60.0; // near front edge
|
||||||
|
|
||||||
|
// ── Jetson Orin NX mount ─────────────────────────────────
|
||||||
|
// ⚠ Verify hole pattern against your carrier board.
|
||||||
|
// Default: 58×49 mm M3 (same as RPi HAT pattern used on Orin NX cards).
|
||||||
|
ORIN_HOLE_X = 58.0;
|
||||||
|
ORIN_HOLE_Y = 49.0;
|
||||||
|
ORIN_HOLE_D = 3.2;
|
||||||
|
ORIN_STANDOFF = 8.0;
|
||||||
|
ORIN_X = 0.0;
|
||||||
|
ORIN_Y = -(ROVER_L/2 - 55.0); // near rear edge
|
||||||
|
|
||||||
|
// ── Motor bracket attachment bolt pattern ────────────────
|
||||||
|
// 2× M5 bolts through deck edge at each motor corner.
|
||||||
|
MOT_BOLT_D = 5.3; // M5 clearance
|
||||||
|
MOT_BOLT_SPC = 30.0; // bolt spacing fore-aft at each motor position
|
||||||
|
|
||||||
|
// ── Lightening holes ──────────────────────────────────────
|
||||||
|
LH_D = 55.0;
|
||||||
|
|
||||||
|
// ── Fasteners ─────────────────────────────────────────────
|
||||||
|
M3_D = 3.2;
|
||||||
|
M4_D = 4.3;
|
||||||
|
M5_D = 5.3;
|
||||||
|
|
||||||
|
$fn = 64;
|
||||||
|
e = 0.01;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// rounded_plate_2d()
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module rounded_plate_2d(l, w, r) {
|
||||||
|
offset(r=r, $fn=32) offset(r=-r)
|
||||||
|
square([l, w], center=true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// rover_deck()
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
module rover_deck() {
|
||||||
|
tray_w = BATT_X_DIM + 2*TRAY_MARGIN; // 430 mm
|
||||||
|
tray_l = BATT_Y_DIM * BATT_N + 2*TRAY_MARGIN; // 186 or 362 mm
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
// ── Deck plate ────────────────────────────────
|
||||||
|
translate([0, 0, -DECK_T])
|
||||||
|
linear_extrude(DECK_T)
|
||||||
|
rounded_plate_2d(ROVER_W, ROVER_L, DECK_R);
|
||||||
|
|
||||||
|
// ── Battery tray opening (centred, through deck) ──
|
||||||
|
translate([-tray_w/2, -tray_l/2, -DECK_T - e])
|
||||||
|
cube([tray_w, tray_l, DECK_T + 2*e]);
|
||||||
|
|
||||||
|
// ── Lightening holes ──────────────────────────
|
||||||
|
// 3 columns × 2 rows, outside battery opening
|
||||||
|
for (hx = [-ROVER_W/4, 0, ROVER_W/4])
|
||||||
|
for (hy = [-(tray_l/2 + LH_D/2 + 20),
|
||||||
|
(tray_l/2 + LH_D/2 + 20)])
|
||||||
|
if (abs(hy) < ROVER_L/2 - LH_D/2 - 10)
|
||||||
|
translate([hx, hy, -DECK_T - e])
|
||||||
|
cylinder(d=LH_D, h=DECK_T + 2*e);
|
||||||
|
|
||||||
|
// ── FC mount holes ────────────────────────────
|
||||||
|
for (fx=[-FC_SPACING/2, FC_SPACING/2])
|
||||||
|
for (fy=[-FC_SPACING/2, FC_SPACING/2])
|
||||||
|
translate([FC_X + fx, FC_Y + fy, -DECK_T - e])
|
||||||
|
cylinder(d=FC_HOLE_D, h=DECK_T + 2*e);
|
||||||
|
|
||||||
|
// ── Orin mount holes ──────────────────────────
|
||||||
|
for (ox=[-ORIN_HOLE_X/2, ORIN_HOLE_X/2])
|
||||||
|
for (oy=[-ORIN_HOLE_Y/2, ORIN_HOLE_Y/2])
|
||||||
|
translate([ORIN_X + ox, ORIN_Y + oy, -DECK_T - e])
|
||||||
|
cylinder(d=ORIN_HOLE_D, h=DECK_T + 2*e);
|
||||||
|
|
||||||
|
// ── Motor bracket bolt holes (4 corners × 2 bolts) ──
|
||||||
|
for (sx=[-1,1], sy=[-1,1])
|
||||||
|
for (by=[-MOT_BOLT_SPC/2, MOT_BOLT_SPC/2])
|
||||||
|
translate([sx*ROVER_W/2 - sx*(DECK_T/2 + e),
|
||||||
|
sy*AXLE_BASE/2 + by,
|
||||||
|
-DECK_T - e])
|
||||||
|
rotate([0, 90, 0])
|
||||||
|
cylinder(d=MOT_BOLT_D, h=DECK_T + 2*e);
|
||||||
|
|
||||||
|
// ── Stem bore through deck ────────────────────
|
||||||
|
translate([0, 0, -DECK_T - e])
|
||||||
|
cylinder(d=STEM_BORE, h=DECK_T + 2*e);
|
||||||
|
|
||||||
|
// ── Cable routing slots (×2 per side, fore and aft) ──
|
||||||
|
for (cy=[-ROVER_L/2 - e, ROVER_L/2 - 16])
|
||||||
|
for (cx=[-55, 55])
|
||||||
|
translate([cx - 7, cy, -DECK_T - e])
|
||||||
|
cube([14, 16, DECK_T + 2*e]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Stem collar (raised boss) ─────────────────────
|
||||||
|
difference() {
|
||||||
|
cylinder(d=STEM_COLLAR_OD, h=STEM_COLLAR_H);
|
||||||
|
translate([0, 0, -e])
|
||||||
|
cylinder(d=STEM_BORE, h=STEM_COLLAR_H + 2*e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── FC standoff posts (×4) ────────────────────────
|
||||||
|
for (fx=[-FC_SPACING/2, FC_SPACING/2])
|
||||||
|
for (fy=[-FC_SPACING/2, FC_SPACING/2])
|
||||||
|
translate([FC_X + fx, FC_Y + fy, 0])
|
||||||
|
cylinder(d=6, h=FC_STANDOFF_H);
|
||||||
|
|
||||||
|
// ── Orin standoff posts (×4) ──────────────────────
|
||||||
|
for (ox=[-ORIN_HOLE_X/2, ORIN_HOLE_X/2])
|
||||||
|
for (oy=[-ORIN_HOLE_Y/2, ORIN_HOLE_Y/2])
|
||||||
|
translate([ORIN_X + ox, ORIN_Y + oy, 0])
|
||||||
|
cylinder(d=6, h=ORIN_STANDOFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
// Render selector
|
||||||
|
// ─────────────────────────────────────────────────────────
|
||||||
|
if (RENDER == "assembly") {
|
||||||
|
color("Silver", 0.90) rover_deck();
|
||||||
|
|
||||||
|
// Phantom battery packs (2 × laid flat)
|
||||||
|
tray_w = BATT_X_DIM + 2*TRAY_MARGIN;
|
||||||
|
tray_l = BATT_Y_DIM * BATT_N + 2*TRAY_MARGIN;
|
||||||
|
for (pn = [0 : BATT_N - 1])
|
||||||
|
color("Gold", 0.30)
|
||||||
|
translate([-BATT_X_DIM/2,
|
||||||
|
-BATT_Y_DIM*BATT_N/2 + pn*BATT_Y_DIM,
|
||||||
|
-(DECK_T + BATT_FLOOR_T + BATT_PACK_H)])
|
||||||
|
cube([BATT_X_DIM, BATT_Y_DIM, BATT_PACK_H]);
|
||||||
|
|
||||||
|
// Phantom stem stub
|
||||||
|
color("Silver", 0.25)
|
||||||
|
translate([0, 0, STEM_COLLAR_H])
|
||||||
|
cylinder(d=25, h=400);
|
||||||
|
|
||||||
|
// Motor position markers (spheres at axle CLs)
|
||||||
|
axle_z = AXLE_H - (DECK_BOT_H + DECK_T); // above deck top
|
||||||
|
for (sx=[-1,1], sy=[-1,1])
|
||||||
|
color("Tomato", 0.5)
|
||||||
|
translate([sx*TRACK_W/2, sy*AXLE_BASE/2, axle_z])
|
||||||
|
sphere(d=20);
|
||||||
|
|
||||||
|
} else if (RENDER == "deck") {
|
||||||
|
rover_deck();
|
||||||
|
|
||||||
|
} else if (RENDER == "deck_2d") {
|
||||||
|
projection(cut=true)
|
||||||
|
translate([0, 0, -DECK_T/2])
|
||||||
|
rover_deck();
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user