275
chassis/uwb_anchor_mount.scad
Normal file
275
chassis/uwb_anchor_mount.scad
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
// ============================================================
|
||||||
|
// uwb_anchor_mount.scad — Stem-Mounted UWB Anchor Rev A
|
||||||
|
// Agent: sl-mechanical 2026-03-01
|
||||||
|
// Closes issues #57, #62
|
||||||
|
// ============================================================
|
||||||
|
// Clamp-on bracket for 2× MaUWB ESP32-S3 anchor modules on
|
||||||
|
// SaltyBot 25 mm OD vertical stem.
|
||||||
|
// Anchors spaced ANCHOR_SPACING = 250 mm apart.
|
||||||
|
//
|
||||||
|
// Features:
|
||||||
|
// • Split D-collar with M4 clamping bolts + M4 set screw
|
||||||
|
// • Anti-rotation flat tab that keys against a small pin
|
||||||
|
// OR printed key tab that registers on the stem flat (if stem
|
||||||
|
// has a ground flat) — see ANTI_ROT_MODE parameter
|
||||||
|
// • Module bracket: faces outward, tilted 10° from vertical
|
||||||
|
// so antenna clears stem and faces horizon
|
||||||
|
// • USB cable channel (power from Orin via USB-A) on collar
|
||||||
|
// • Tool-free capture: M4 thumbscrews (slot-head, hand-tighten)
|
||||||
|
// • UWB antenna area: NO material within 10 mm of PCB top face
|
||||||
|
//
|
||||||
|
// Components per mount:
|
||||||
|
// 2× collar_half print in PLA/PETG, flat-face-down
|
||||||
|
// 1× module_bracket print in PLA/PETG, flat-face-down
|
||||||
|
//
|
||||||
|
// RENDER options:
|
||||||
|
// "assembly" single mount assembled (default)
|
||||||
|
// "collar_front" front collar half for slicing (×2 per mount × 2 mounts = 4)
|
||||||
|
// "collar_rear" rear collar half
|
||||||
|
// "bracket" module bracket (×2 mounts)
|
||||||
|
// "pair" both mounts on 350 mm stem section
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
RENDER = "assembly";
|
||||||
|
|
||||||
|
// ── ⚠ Verify with calipers ───────────────────────────────────
|
||||||
|
MAWB_L = 50.0; // PCB length
|
||||||
|
MAWB_W = 25.0; // PCB width
|
||||||
|
MAWB_H = 10.0; // PCB + components
|
||||||
|
MAWB_HOLE_X = 43.0; // M2 mounting hole X span
|
||||||
|
MAWB_HOLE_Y = 20.0; // M2 mounting hole Y span
|
||||||
|
M2_D = 2.2; // M2 clearance
|
||||||
|
|
||||||
|
// ── Stem ─────────────────────────────────────────────────────
|
||||||
|
STEM_OD = 25.0;
|
||||||
|
STEM_BORE = 25.4; // +0.4 clearance
|
||||||
|
WALL = 2.0; // wall thickness (used in thumbscrew recess)
|
||||||
|
|
||||||
|
// ── Collar ───────────────────────────────────────────────────
|
||||||
|
COL_OD = 52.0;
|
||||||
|
COL_H = 30.0; // taller than sensor-head collar for rigidity
|
||||||
|
COL_BOLT_X = 19.0; // M4 bolt CL from stem axis
|
||||||
|
COL_BOLT_D = 4.5; // M4 clearance
|
||||||
|
THUMB_HEAD_D= 8.0; // M4 thumbscrew head OD (slot for access)
|
||||||
|
COL_NUT_W = 7.0; // M4 hex nut A/F
|
||||||
|
COL_NUT_H = 3.4;
|
||||||
|
|
||||||
|
// Anti-rotation flat tab: a 3 mm wall tab that protrudes radially
|
||||||
|
// and bears against the bracket arm, preventing axial rotation
|
||||||
|
// without needing a stem flat.
|
||||||
|
ANTI_ROT_T = 3.0; // tab thickness (radial)
|
||||||
|
ANTI_ROT_W = 8.0; // tab width (tangential)
|
||||||
|
ANTI_ROT_Z = 4.0; // distance from collar base
|
||||||
|
|
||||||
|
// USB cable channel: groove on collar outer surface, runs Z direction
|
||||||
|
// Cable routes from anchor module down to base
|
||||||
|
USB_CHAN_W = 9.0; // channel width (fits USB-A cable Ø6 mm)
|
||||||
|
USB_CHAN_D = 5.0; // channel depth
|
||||||
|
|
||||||
|
// ── Module bracket ───────────────────────────────────────────
|
||||||
|
ARM_L = 20.0; // arm length from collar OD to bracket face
|
||||||
|
ARM_W = MAWB_W + 6.0; // bracket width (Y, includes side walls)
|
||||||
|
ARM_H = 6.0; // arm thickness (Z)
|
||||||
|
BRKT_TILT = 10.0; // tilt outward from vertical (antenna faces horizon)
|
||||||
|
|
||||||
|
BRKT_BACK_T = 3.0; // bracket back wall (module sits against this)
|
||||||
|
BRKT_SIDE_T = 2.0; // bracket side walls
|
||||||
|
|
||||||
|
M2_STNDFF = 3.0; // M2 standoff height
|
||||||
|
M2_STNDFF_OD= 4.5;
|
||||||
|
|
||||||
|
// USB port access notch in bracket side wall (8×5 mm)
|
||||||
|
USB_NOTCH_W = 10.0;
|
||||||
|
USB_NOTCH_H = 7.0;
|
||||||
|
|
||||||
|
// ── Spacing ───────────────────────────────────────────────────
|
||||||
|
ANCHOR_SPACING = 250.0; // centre-to-centre Z separation
|
||||||
|
|
||||||
|
$fn = 64;
|
||||||
|
e = 0.01;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// collar_half(side)
|
||||||
|
// split at Y=0 plane. Bracket arm on front (+Y) half.
|
||||||
|
// Print flat-face-down.
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module collar_half(side = "front") {
|
||||||
|
y_front = (side == "front");
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// D-shaped body
|
||||||
|
intersection() {
|
||||||
|
cylinder(d=COL_OD, h=COL_H);
|
||||||
|
translate([-COL_OD/2, y_front ? 0 : -COL_OD/2, 0])
|
||||||
|
cube([COL_OD, COL_OD/2, COL_H]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anti-rotation tab (front half only, at +X side)
|
||||||
|
if (y_front) {
|
||||||
|
translate([COL_OD/2, -ANTI_ROT_W/2, ANTI_ROT_Z])
|
||||||
|
cube([ANTI_ROT_T, ANTI_ROT_W,
|
||||||
|
COL_H - ANTI_ROT_Z - 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bracket arm attachment boss (front half only, top centre)
|
||||||
|
if (y_front) {
|
||||||
|
translate([-ARM_W/2, COL_OD/2, COL_H * 0.3])
|
||||||
|
cube([ARM_W, ARM_L, COL_H * 0.4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Stem bore ─────────────────────────────────────────
|
||||||
|
translate([0,0,-e])
|
||||||
|
cylinder(d=STEM_BORE, h=COL_H + 2*e);
|
||||||
|
|
||||||
|
// ── M4 clamping bolt holes (Y direction) ──────────────
|
||||||
|
for (bx=[-COL_BOLT_X, COL_BOLT_X]) {
|
||||||
|
translate([bx, y_front ? COL_OD/2 : 0, COL_H/2])
|
||||||
|
rotate([90,0,0])
|
||||||
|
cylinder(d=COL_BOLT_D, h=COL_OD/2 + e);
|
||||||
|
// Thumbscrew head recess on outer face (front only — access side)
|
||||||
|
if (y_front) {
|
||||||
|
translate([bx, COL_OD/2 - WALL, COL_H/2])
|
||||||
|
rotate([90,0,0])
|
||||||
|
cylinder(d=THUMB_HEAD_D, h=8 + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── M4 hex nut pockets (rear half) ────────────────────
|
||||||
|
if (!y_front) {
|
||||||
|
for (bx=[-COL_BOLT_X, COL_BOLT_X]) {
|
||||||
|
translate([bx, -(COL_OD/4 + e), COL_H/2])
|
||||||
|
rotate([90,0,0])
|
||||||
|
cylinder(d=COL_NUT_W/cos(30), h=COL_NUT_H + e,
|
||||||
|
$fn=6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Set screw (height lock, front half) ───────────────
|
||||||
|
if (y_front) {
|
||||||
|
translate([0, COL_OD/2, COL_H * 0.8])
|
||||||
|
rotate([90,0,0])
|
||||||
|
cylinder(d=COL_BOLT_D,
|
||||||
|
h=COL_OD/2 - STEM_BORE/2 + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── USB cable routing channel (rear half, −X side) ────
|
||||||
|
if (!y_front) {
|
||||||
|
translate([-COL_OD/2, -USB_CHAN_W/2, -e])
|
||||||
|
cube([USB_CHAN_D, USB_CHAN_W, COL_H + 2*e]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── M4 hole through arm boss (Z direction, for bracket bolt) ─
|
||||||
|
if (y_front) {
|
||||||
|
for (dx=[-ARM_W/4, ARM_W/4])
|
||||||
|
translate([dx, COL_OD/2 + ARM_L/2, COL_H * 0.35])
|
||||||
|
cylinder(d=COL_BOLT_D, h=COL_H * 0.35 + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// module_bracket()
|
||||||
|
// Bolts to collar arm boss. Holds MaUWB PCB facing outward.
|
||||||
|
// Tilted BRKT_TILT° from vertical — antenna clears stem.
|
||||||
|
// Print flat-face-down (back wall on bed).
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module module_bracket() {
|
||||||
|
bk = BRKT_BACK_T;
|
||||||
|
sd = BRKT_SIDE_T;
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// ── Back wall (mounts to collar arm boss) ─────────
|
||||||
|
cube([ARM_W, bk, MAWB_H + M2_STNDFF + 6]);
|
||||||
|
|
||||||
|
// ── Side walls ────────────────────────────────────
|
||||||
|
for (sx=[0, ARM_W - sd])
|
||||||
|
translate([sx, bk, 0])
|
||||||
|
cube([sd, MAWB_L + 2, MAWB_H + M2_STNDFF + 6]);
|
||||||
|
|
||||||
|
// ── M2 standoff posts (PCB mounts to these) ───────
|
||||||
|
for (hx=[0, MAWB_HOLE_X], hy=[0, MAWB_HOLE_Y])
|
||||||
|
translate([(ARM_W - MAWB_HOLE_X)/2 + hx,
|
||||||
|
bk + (MAWB_L - MAWB_HOLE_Y)/2 + hy,
|
||||||
|
0])
|
||||||
|
cylinder(d=M2_STNDFF_OD, h=M2_STNDFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── M2 bores through standoffs ────────────────────────
|
||||||
|
for (hx=[0, MAWB_HOLE_X], hy=[0, MAWB_HOLE_Y])
|
||||||
|
translate([(ARM_W - MAWB_HOLE_X)/2 + hx,
|
||||||
|
bk + (MAWB_L - MAWB_HOLE_Y)/2 + hy,
|
||||||
|
-e])
|
||||||
|
cylinder(d=M2_D, h=M2_STNDFF + e);
|
||||||
|
|
||||||
|
// ── Antenna clearance cutout in back wall ─────────────
|
||||||
|
// Open slot near top of back wall so antenna is unobstructed
|
||||||
|
translate([sd, -e, M2_STNDFF + 2])
|
||||||
|
cube([ARM_W - 2*sd, bk + 2*e, MAWB_H]);
|
||||||
|
|
||||||
|
// ── USB port access notch on one side wall ────────────
|
||||||
|
translate([-e, bk + 2, M2_STNDFF - 1])
|
||||||
|
cube([sd + 2*e, USB_NOTCH_W, USB_NOTCH_H]);
|
||||||
|
|
||||||
|
// ── Mounting holes to collar arm boss (×2) ────────────
|
||||||
|
for (dx=[-ARM_W/4, ARM_W/4])
|
||||||
|
translate([ARM_W/2 + dx, bk + ARM_L/2, -e])
|
||||||
|
cylinder(d=COL_BOLT_D, h=6 + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// single_anchor_assembly()
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module single_anchor_assembly(show_phantom=false) {
|
||||||
|
// Collar
|
||||||
|
color("SteelBlue", 0.9) collar_half("front");
|
||||||
|
color("CornflowerBlue", 0.9) mirror([0,1,0]) collar_half("rear");
|
||||||
|
|
||||||
|
// Bracket tilted BRKT_TILT° outward from top of arm boss
|
||||||
|
color("LightSteelBlue", 0.85)
|
||||||
|
translate([0, COL_OD/2 + ARM_L, COL_H * 0.3])
|
||||||
|
rotate([BRKT_TILT, 0, 0])
|
||||||
|
translate([-ARM_W/2, 0, 0])
|
||||||
|
module_bracket();
|
||||||
|
|
||||||
|
// Phantom UWB PCB
|
||||||
|
if (show_phantom)
|
||||||
|
color("ForestGreen", 0.4)
|
||||||
|
translate([-MAWB_L/2,
|
||||||
|
COL_OD/2 + ARM_L + BRKT_BACK_T,
|
||||||
|
COL_H * 0.3 + M2_STNDFF])
|
||||||
|
cube([MAWB_L, MAWB_W, MAWB_H]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Render selector
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
if (RENDER == "assembly") {
|
||||||
|
single_anchor_assembly(show_phantom=true);
|
||||||
|
|
||||||
|
} else if (RENDER == "collar_front") {
|
||||||
|
collar_half("front");
|
||||||
|
|
||||||
|
} else if (RENDER == "collar_rear") {
|
||||||
|
collar_half("rear");
|
||||||
|
|
||||||
|
} else if (RENDER == "bracket") {
|
||||||
|
module_bracket();
|
||||||
|
|
||||||
|
} else if (RENDER == "pair") {
|
||||||
|
// Both anchors at 250 mm spacing on a stem stub
|
||||||
|
color("Silver", 0.2)
|
||||||
|
translate([0, 0, -50])
|
||||||
|
cylinder(d=STEM_OD, h=ANCHOR_SPACING + COL_H + 100);
|
||||||
|
|
||||||
|
// Lower anchor (Z = 0)
|
||||||
|
single_anchor_assembly(show_phantom=true);
|
||||||
|
|
||||||
|
// Upper anchor (Z = ANCHOR_SPACING)
|
||||||
|
translate([0, 0, ANCHOR_SPACING])
|
||||||
|
single_anchor_assembly(show_phantom=true);
|
||||||
|
}
|
||||||
|
|
||||||
204
chassis/uwb_assembly.md
Normal file
204
chassis/uwb_assembly.md
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
# SaltyBot UWB System — Assembly Notes + BOM
|
||||||
|
**Rev A — 2026-03-01 — sl-mechanical**
|
||||||
|
**Issues: #57, #61, #62**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## System Overview
|
||||||
|
|
||||||
|
Follow-me UWB ranging using 3× MaUWB ESP32-S3 modules:
|
||||||
|
|
||||||
|
| Role | Qty | Location | File |
|
||||||
|
|------|-----|----------|------|
|
||||||
|
| Tag | 1 | Operator belt ("Tee") | `uwb_tag_enclosure.scad` |
|
||||||
|
| Anchor | 2 | Robot stem, 250 mm apart | `uwb_anchor_mount.scad` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Antenna Clearance — CRITICAL
|
||||||
|
|
||||||
|
The DW3000 UWB chip antenna requires:
|
||||||
|
- **10 mm clear zone** around antenna — no metal, no carbon fibre, no metal-fill filament
|
||||||
|
- Use **plain PLA or PETG** only in these parts (no conductive additives)
|
||||||
|
- Tag lid has an **open window** directly over the PCB antenna area
|
||||||
|
- Anchor bracket **back wall has a cutout** behind the antenna section of the PCB
|
||||||
|
- When installing modules, orient antenna end **away from stem** (faces outward)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part A — UWB Tag Enclosure (`uwb_tag_enclosure.scad`)
|
||||||
|
|
||||||
|
### Printed parts
|
||||||
|
|
||||||
|
| # | RENDER | Qty | Material | Settings |
|
||||||
|
|---|--------|-----|----------|----------|
|
||||||
|
| 1 | `body` | 1 | PETG | 4 perims, 35% infill, 0.2 mm layer |
|
||||||
|
| 2 | `lid` | 1 | PETG | 4 perims, 35% infill |
|
||||||
|
| 3 | `tpu_bumper` | 1 | TPU 95A | 3 perims, 20% infill, 25 mm/s |
|
||||||
|
|
||||||
|
> **Print orientation:** body — floor on bed; lid — inside face down; TPU bumper — flat.
|
||||||
|
|
||||||
|
### Internal layout diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
X− ←────────── ~75 mm ──────────→ X+
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
USB → │[TP4056] [ 18650 cell ] │
|
||||||
|
│─────────────────────────────│
|
||||||
|
│ [ MaUWB ESP32-S3 PCB ] │ ← antenna faces UP
|
||||||
|
└──────────────────────────────┘
|
||||||
|
↑ ↑
|
||||||
|
micro-USB LED window
|
||||||
|
(charging) (Y+ face, small hole)
|
||||||
|
|
||||||
|
Power switch cutout: Y− face, centred
|
||||||
|
Belt clip: Y− face (back)
|
||||||
|
```
|
||||||
|
|
||||||
|
### IP44 seam
|
||||||
|
|
||||||
|
Lid rim overlaps body 4 mm with a 2-turn labyrinth ridge (water must turn
|
||||||
|
90° twice). No holes on the top face. All ports on side/back faces.
|
||||||
|
**Not suitable for rain immersion — use for light splash protection only.**
|
||||||
|
|
||||||
|
### Heat-set insert option
|
||||||
|
|
||||||
|
For improved thread strength, replace M2 clearance standoffs with **M2 × 3 mm
|
||||||
|
heat-set brass inserts** pressed into the standoff posts with a soldering iron.
|
||||||
|
|
||||||
|
### Fasteners
|
||||||
|
|
||||||
|
| # | Spec | Qty | Use |
|
||||||
|
|---|------|-----|-----|
|
||||||
|
| 4 | M2 × 6 BHCS | 4 | MaUWB PCB to standoffs |
|
||||||
|
| 5 | M2 hex nut | 4 | Alternative if no heat-set inserts |
|
||||||
|
| 6 | M3 × 8 SHCS | 2 | Belt clip to enclosure back |
|
||||||
|
| 7 | M3 hex nut | 2 | Captured in clip back plate |
|
||||||
|
|
||||||
|
### Assembly sequence — tag
|
||||||
|
|
||||||
|
1. Install TP4056 board in body, micro-USB port aligned with cutout
|
||||||
|
2. Solder TP4056 leads to 18650 spring contacts (or use 18650 holder PCB)
|
||||||
|
3. Snap 18650 into battery cradle (+ end toward spring contact at X+)
|
||||||
|
4. Seat MaUWB PCB on M2 standoffs; tighten M2 × 6 bolts (0.3 N·m — soft)
|
||||||
|
5. Route USB data + power cable from MaUWB to TP4056 B+ / B− pads
|
||||||
|
6. Press power switch into cutout (Y− face)
|
||||||
|
7. Close lid — press corners until 4 snap clips engage (audible click ×4)
|
||||||
|
8. Slide TPU bumper sleeve onto body from below
|
||||||
|
9. Attach belt clip to Y− face with 2× M3 × 8
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Part B — Anchor Mounts (`uwb_anchor_mount.scad`)
|
||||||
|
|
||||||
|
### Printed parts (per mount × 2 mounts)
|
||||||
|
|
||||||
|
| # | RENDER | Qty per mount | Total | Material | Notes |
|
||||||
|
|---|--------|---------------|-------|----------|-------|
|
||||||
|
| 10 | `collar_front` | 1 | 2 | PETG | Flat-face-down; has thumbscrew recesses |
|
||||||
|
| 11 | `collar_rear` | 1 | 2 | PETG | Has hex nut pockets + USB cable channel |
|
||||||
|
| 12 | `bracket` | 1 | 2 | PETG | Flat-face-down; back wall on bed |
|
||||||
|
|
||||||
|
### Anti-rotation
|
||||||
|
|
||||||
|
The front collar half has a **flat tab** (3 × 8 mm radial tab at +X) that
|
||||||
|
protrudes from the collar outer surface. This tab:
|
||||||
|
- Bears against the module bracket arm, preventing rotation during clamping
|
||||||
|
- Creates a positive mechanical register — mount always faces the same direction
|
||||||
|
- No modification to the stem required
|
||||||
|
|
||||||
|
### Anchor positioning on stem
|
||||||
|
|
||||||
|
```
|
||||||
|
TOP OF STEM
|
||||||
|
│
|
||||||
|
──┼── ← Sensor head (sensor_head.scad, at ~800–900 mm)
|
||||||
|
│
|
||||||
|
══╬══ ← Upper anchor (ANCHOR 2) ┐
|
||||||
|
│ │ 250 mm
|
||||||
|
══╬══ ← Lower anchor (ANCHOR 1) ┘
|
||||||
|
│
|
||||||
|
──┼── ← Battery carousel (stem_battery_clamp.scad)
|
||||||
|
│
|
||||||
|
BOTTOM OF STEM (base plate)
|
||||||
|
```
|
||||||
|
|
||||||
|
Recommended Z positions (above base plate):
|
||||||
|
- Anchor 1: **450 mm** (just above battery carousel top)
|
||||||
|
- Anchor 2: **700 mm**
|
||||||
|
|
||||||
|
This places anchors in the mid-stem region, maximising horizontal separation
|
||||||
|
from each other and from nearby metal (battery packs, base plate).
|
||||||
|
|
||||||
|
### USB cable routing
|
||||||
|
|
||||||
|
Each anchor is powered via USB-A from the Jetson Orin. Cable routing:
|
||||||
|
1. Cable exits Orin USB hub, runs up stem through cable ties
|
||||||
|
2. Enters anchor bracket through USB notch on left side wall
|
||||||
|
3. Plugs into MaUWB USB-C port (programming and power)
|
||||||
|
4. Excess cable loops into rear collar USB channel groove, held with a cable tie
|
||||||
|
|
||||||
|
### Fasteners (per mount)
|
||||||
|
|
||||||
|
| # | Spec | Qty | Use |
|
||||||
|
|---|------|-----|-----|
|
||||||
|
| 13 | M4 × 25 SHCS (thumbscrew head) | 2 | Collar clamping bolts (tool-free: slot for coin) |
|
||||||
|
| 14 | M4 hex nut | 2 | Captured in rear collar half |
|
||||||
|
| 15 | M4 × 10 set screw | 1 | Collar height lock (front half) |
|
||||||
|
| 16 | M4 × 20 SHCS | 2 | Bracket to collar arm boss |
|
||||||
|
| 17 | M4 hex nut | 2 | Under collar boss for bracket bolts |
|
||||||
|
| 18 | M2 × 6 BHCS | 4 | MaUWB PCB to bracket standoffs |
|
||||||
|
| 19 | M2 hex nut | 4 | PCB standoff nuts |
|
||||||
|
|
||||||
|
### Assembly sequence — anchor (×2)
|
||||||
|
|
||||||
|
1. Press M4 hex nuts into collar rear half nut pockets
|
||||||
|
2. Press M2 hex nuts into bracket standoff counterbores
|
||||||
|
3. Seat MaUWB PCB in bracket on M2 standoffs; tighten M2 × 6 BHCS (0.3 N·m)
|
||||||
|
4. Bolt bracket to collar front-half arm boss with 2× M4 × 20
|
||||||
|
5. Align anti-rotation tab with bracket arm edge
|
||||||
|
6. Wrap collar halves around stem at desired height
|
||||||
|
7. Align micro-USB / USB-C port direction, tighten M4 thumbscrews finger-tight
|
||||||
|
8. Tighten set screw on front half to lock height
|
||||||
|
9. Route USB cable through rear channel, cable-tie every ~100 mm along stem
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Full Mass Estimate
|
||||||
|
|
||||||
|
| Part | Material | Est. mass |
|
||||||
|
|------|----------|-----------|
|
||||||
|
| Tag body + lid (PETG) | PETG | ~45 g |
|
||||||
|
| Tag TPU bumper | TPU | ~12 g |
|
||||||
|
| 18650 cell | Li-ion | ~47 g |
|
||||||
|
| TP4056 + MaUWB PCBs | PCB | ~20 g |
|
||||||
|
| Tag total | | **~130 g** |
|
||||||
|
| Anchor collar set × 2 (×2) | PETG | ~80 g |
|
||||||
|
| Anchor brackets × 2 | PETG | ~40 g |
|
||||||
|
| MaUWB PCBs × 2 | PCB | ~30 g |
|
||||||
|
| Anchor fasteners | SS | ~20 g |
|
||||||
|
| **Total (tag + 2 anchors)** | | **~300 g** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bill of Materials Summary
|
||||||
|
|
||||||
|
| # | Description | Qty | Source hint |
|
||||||
|
|---|-------------|-----|-------------|
|
||||||
|
| A | MaUWB ESP32-S3 module | 3 | AliExpress / MakerFabs |
|
||||||
|
| B | 18650 Li-ion cell (≥2000 mAh) | 1 | Panasonic NCR18650B or equiv. |
|
||||||
|
| C | TP4056 micro-USB charger board | 1 | Standard TP4056 module |
|
||||||
|
| D | Slide power switch 13×7 mm | 1 | SS-12D00 or equiv. |
|
||||||
|
| E | M2 × 6 BHCS | 12 | (4 tag + 4 anchor-1 + 4 anchor-2) |
|
||||||
|
| F | M2 hex nut | 12 | |
|
||||||
|
| G | M3 × 8 SHCS | 2 | Belt clip |
|
||||||
|
| H | M3 hex nut | 2 | |
|
||||||
|
| I | M4 × 25 thumbscrew SHCS | 4 | Slot-head preferred for tool-free use |
|
||||||
|
| J | M4 × 20 SHCS | 4 | Bracket-to-collar |
|
||||||
|
| K | M4 × 10 set screw | 2 | Height lock |
|
||||||
|
| L | M4 hex nut | 8 | |
|
||||||
|
| M | USB-A to USB-C cable 1 m | 2 | Anchor power from Orin |
|
||||||
|
| N | PETG filament | ~200 g | Any brand |
|
||||||
|
| O | TPU 95A filament | ~30 g | For tag bumper |
|
||||||
|
| P | Loctite 243 blue | 1 | Structural M4 bolts |
|
||||||
|
| Q | Cable ties 100 mm | 10 | Stem cable management |
|
||||||
369
chassis/uwb_tag_enclosure.scad
Normal file
369
chassis/uwb_tag_enclosure.scad
Normal file
@ -0,0 +1,369 @@
|
|||||||
|
// ============================================================
|
||||||
|
// uwb_tag_enclosure.scad — Wearable UWB Tag Rev B 2026-03-01
|
||||||
|
// Agent: sl-mechanical
|
||||||
|
// Closes issues #57, #61
|
||||||
|
// ============================================================
|
||||||
|
// Belt-clip enclosure for "follow-me" UWB tag worn by operator.
|
||||||
|
//
|
||||||
|
// Components:
|
||||||
|
// MaUWB ESP32-S3 module ~50 × 25 × 10 mm PCB
|
||||||
|
// TP4056 charger board ~25 × 19 mm, micro-USB port
|
||||||
|
// 18650 Li-ion cell Ø18 × 65 mm
|
||||||
|
//
|
||||||
|
// ⚠ VERIFY WITH CALIPERS BEFORE PRINTING:
|
||||||
|
// MAWB_L, MAWB_W, MAWB_H — UWB module
|
||||||
|
// TP_L, TP_W — TP4056 board
|
||||||
|
// TP_USB_W, TP_USB_H — micro-USB receptacle
|
||||||
|
// SW_W, SW_H — power switch body
|
||||||
|
//
|
||||||
|
// Key design decisions:
|
||||||
|
// • UWB antenna window (open rectangle) in LID — no material
|
||||||
|
// within 10 mm of antenna area; antenna faces up
|
||||||
|
// • IP44-ish: lid overlaps body 4 mm + 2-turn labyrinth seam;
|
||||||
|
// all ports on side faces, NO holes in top face
|
||||||
|
// • TPU bumper sleeve snaps around body bottom edge (drop protection)
|
||||||
|
// • Micro-USB on short face (X−), power switch on long face (Y−)
|
||||||
|
// • Belt clip integrated on back face (Y−)
|
||||||
|
//
|
||||||
|
// Internal layout (cross-section view from top):
|
||||||
|
//
|
||||||
|
// Y+ ┌──────────────────────────────────────────┐
|
||||||
|
// │ [ MaUWB PCB 50×25mm flat ] │
|
||||||
|
// │ [TP4056] ──── [ 18650 cell ] ────── │
|
||||||
|
// Y− └──────────────────────────────────────────┘
|
||||||
|
// X− X+
|
||||||
|
//
|
||||||
|
// RENDER options:
|
||||||
|
// "assembly" closed box (default)
|
||||||
|
// "body" lower shell for slicing
|
||||||
|
// "lid" snap-fit lid for slicing
|
||||||
|
// "tpu_bumper" TPU edge sleeve for slicing (print in TPU 95A)
|
||||||
|
// "body_2d" bottom projection → DXF
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
RENDER = "assembly";
|
||||||
|
|
||||||
|
// ── ⚠ Verify-before-print ────────────────────────────────────
|
||||||
|
// MaUWB ESP32-S3
|
||||||
|
MAWB_L = 50.0; // PCB length (X)
|
||||||
|
MAWB_W = 25.0; // PCB width (Y)
|
||||||
|
MAWB_H = 10.0; // PCB + tallest component (Z)
|
||||||
|
MAWB_HOLE_X = 43.0; // M2 mounting hole spacing X (verify)
|
||||||
|
MAWB_HOLE_Y = 20.0; // M2 mounting hole spacing Y (verify)
|
||||||
|
M2_D = 2.2; // M2 clearance
|
||||||
|
M2_STNDFF = 3.0; // standoff height (PCB proud of tray floor)
|
||||||
|
M2_STNDFF_OD= 4.5; // standoff post OD
|
||||||
|
|
||||||
|
// TP4056 charger
|
||||||
|
TP_L = 25.0; // PCB length (X, at X− end)
|
||||||
|
TP_W = 19.0; // PCB width (Y)
|
||||||
|
TP_H = 5.0; // PCB + components (Z)
|
||||||
|
TP_USB_W = 8.0; // micro-USB receptacle width
|
||||||
|
TP_USB_H = 3.5; // micro-USB receptacle height
|
||||||
|
|
||||||
|
// Power switch (slide or toggle, 13×7 mm body)
|
||||||
|
SW_W = 13.0; // switch body length (X)
|
||||||
|
SW_H = 7.0; // switch body height (Z)
|
||||||
|
SW_BEZEL_W = 8.0; // switch cutout width in wall
|
||||||
|
SW_BEZEL_H = 5.0; // switch cutout height in wall
|
||||||
|
SW_Y_POS = 6.0; // distance from bottom of internal space (Z)
|
||||||
|
|
||||||
|
// 18650 cell
|
||||||
|
BATT_OD = 18.6; // diameter + clearance
|
||||||
|
BATT_L = 65.5; // length + clearance
|
||||||
|
|
||||||
|
// ── Enclosure shell ──────────────────────────────────────────
|
||||||
|
WALL = 2.2; // shell wall thickness
|
||||||
|
FLOOR = 2.5; // floor thickness (bottom face printed)
|
||||||
|
LID_H = 3.0; // lid panel thickness
|
||||||
|
LID_OVLP = 4.0; // lid rim overlap depth (IP44 seal)
|
||||||
|
LID_LBYRTH = 1.0; // labyrinth ridge height
|
||||||
|
LID_LBYRTH_W= 1.2; // labyrinth ridge width
|
||||||
|
|
||||||
|
// Snap clips (×4, one per side)
|
||||||
|
SNAP_W = 8.0;
|
||||||
|
SNAP_T = 1.5;
|
||||||
|
SNAP_H = 1.8;
|
||||||
|
|
||||||
|
// ── Internal component layout ────────────────────────────────
|
||||||
|
// Battery runs in X at Y = INT_W/2 − BATT_OD/2 (left/bottom of bay)
|
||||||
|
// TP4056 at X− end, beside battery in Y
|
||||||
|
// MaUWB PCB flat above battery and TP4056 (stacked)
|
||||||
|
|
||||||
|
// Z stack:
|
||||||
|
// Z=0 body floor
|
||||||
|
// Z=FLOOR interior floor
|
||||||
|
// Z=FLOOR..FLOOR+BATT_OD battery (18 mm dia)
|
||||||
|
// Z=FLOOR+BATT_OD+1 PCB tray floor (1 mm above battery)
|
||||||
|
// Z=PCB_TRAY+M2_STNDFF PCB bottom face
|
||||||
|
// Z=PCB_TRAY+M2_STNDFF+MAWB_H PCB top
|
||||||
|
// + 2 mm clearance + LID
|
||||||
|
PCB_TRAY_Z = FLOOR + BATT_OD + 1.5;
|
||||||
|
PCB_BOT_Z = PCB_TRAY_Z + M2_STNDFF;
|
||||||
|
PCB_TOP_Z = PCB_BOT_Z + MAWB_H;
|
||||||
|
|
||||||
|
// Internal dimensions
|
||||||
|
INT_L = BATT_L + 5.0; // 70.5 mm (battery + wiring room)
|
||||||
|
INT_W = BATT_OD + MAWB_W - 10; // ~33 mm (battery + PCB overlap in Y)
|
||||||
|
INT_H = PCB_TOP_Z - FLOOR + 2.5; // ~31 mm
|
||||||
|
|
||||||
|
// External dimensions
|
||||||
|
EXT_L = INT_L + 2 * WALL;
|
||||||
|
EXT_W = INT_W + 2 * WALL;
|
||||||
|
EXT_H = INT_H + FLOOR;
|
||||||
|
|
||||||
|
// ── Belt clip ─────────────────────────────────────────────────
|
||||||
|
CLIP_H = 58.0; // total clip height
|
||||||
|
CLIP_GAP = 5.5; // belt slot gap (fits 5 mm thick belt)
|
||||||
|
CLIP_BELT_W = 42.0; // belt slot width
|
||||||
|
CLIP_BACK_T = 4.0; // clip back-plate thickness
|
||||||
|
CLIP_FLEX_T = 2.0; // spring arm thickness
|
||||||
|
|
||||||
|
// ── TPU bumper sleeve ─────────────────────────────────────────
|
||||||
|
TPU_T = 4.0; // bumper wall thickness
|
||||||
|
TPU_H = 12.0; // bumper height (covers bottom edge)
|
||||||
|
TPU_CR = 5.0; // outer corner radius
|
||||||
|
|
||||||
|
$fn = 48;
|
||||||
|
e = 0.01;
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module rounded_box(l, w, h, r = 3.5) {
|
||||||
|
hull()
|
||||||
|
for (x=[r, l-r], y=[r, w-r])
|
||||||
|
translate([x, y, 0])
|
||||||
|
cylinder(r=r, h=h);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// enclosure_body() Print: floor on build plate, no supports.
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module enclosure_body() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// ── Outer shell ──────────────────────────────────
|
||||||
|
rounded_box(EXT_L, EXT_W, EXT_H, r = 3.5);
|
||||||
|
|
||||||
|
// ── IP44 labyrinth ridge on top rim ──────────────
|
||||||
|
// Inner ridge that mates with lid groove
|
||||||
|
translate([WALL - LID_LBYRTH_W, WALL - LID_LBYRTH_W,
|
||||||
|
EXT_H - LID_LBYRTH])
|
||||||
|
difference() {
|
||||||
|
rounded_box(INT_L + 2*LID_LBYRTH_W,
|
||||||
|
INT_W + 2*LID_LBYRTH_W,
|
||||||
|
LID_LBYRTH + e, r = 2.5);
|
||||||
|
translate([LID_LBYRTH_W, LID_LBYRTH_W, -e])
|
||||||
|
cube([INT_L, INT_W, LID_LBYRTH + 2*e]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── M2 standoffs for UWB PCB ─────────────────────
|
||||||
|
bx = WALL + (INT_L - MAWB_L)/2;
|
||||||
|
by = WALL + (INT_W - MAWB_W)/2;
|
||||||
|
for (sx=[0, MAWB_HOLE_X], sy=[0, MAWB_HOLE_Y])
|
||||||
|
translate([bx + (MAWB_L - MAWB_HOLE_X)/2 + sx,
|
||||||
|
by + (MAWB_W - MAWB_HOLE_Y)/2 + sy,
|
||||||
|
0])
|
||||||
|
cylinder(d=M2_STNDFF_OD, h=PCB_TRAY_Z + M2_STNDFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Interior cavity ───────────────────────────────────
|
||||||
|
translate([WALL, WALL, FLOOR])
|
||||||
|
cube([INT_L, INT_W, INT_H + e]);
|
||||||
|
|
||||||
|
// ── 18650 battery cradle ──────────────────────────────
|
||||||
|
// Semi-cylindrical channel in floor, Y− side of interior
|
||||||
|
hull() {
|
||||||
|
translate([WALL + 3, WALL + BATT_OD/2, FLOOR])
|
||||||
|
rotate([-90, 0, 90])
|
||||||
|
cylinder(d=BATT_OD, h=BATT_L - 3);
|
||||||
|
}
|
||||||
|
// Positive end spring hole
|
||||||
|
translate([WALL + INT_L - 2, WALL + BATT_OD/2, FLOOR])
|
||||||
|
cylinder(d=8, h=FLOOR + e);
|
||||||
|
|
||||||
|
// ── Micro-USB cutout (X− face) ────────────────────────
|
||||||
|
translate([-e, WALL + (INT_W - TP_USB_W)/2,
|
||||||
|
FLOOR + BATT_OD/2 - TP_USB_H/2 + 1])
|
||||||
|
cube([WALL + 2*e, TP_USB_W, TP_USB_H]);
|
||||||
|
|
||||||
|
// ── Power switch cutout (Y− face) ─────────────────────
|
||||||
|
translate([WALL + (INT_L - SW_W)/2, -e,
|
||||||
|
FLOOR + SW_Y_POS])
|
||||||
|
cube([SW_BEZEL_W, WALL + 2*e, SW_BEZEL_H]);
|
||||||
|
|
||||||
|
// ── Status LED window (Y+ face, small hole) ───────────
|
||||||
|
// TP4056 charge LED and ESP32 LED visible from side
|
||||||
|
translate([WALL + TP_L / 2, EXT_W - WALL - e,
|
||||||
|
FLOOR + BATT_OD + 2])
|
||||||
|
rotate([90, 0, 0])
|
||||||
|
cylinder(d=2.5, h=WALL + 2*e);
|
||||||
|
|
||||||
|
// ── M2 standoff bores ─────────────────────────────────
|
||||||
|
bx = WALL + (INT_L - MAWB_L)/2;
|
||||||
|
by = WALL + (INT_W - MAWB_W)/2;
|
||||||
|
for (sx=[0, MAWB_HOLE_X], sy=[0, MAWB_HOLE_Y])
|
||||||
|
translate([bx + (MAWB_L - MAWB_HOLE_X)/2 + sx,
|
||||||
|
by + (MAWB_W - MAWB_HOLE_Y)/2 + sy,
|
||||||
|
-e])
|
||||||
|
cylinder(d=M2_D, h=PCB_TRAY_Z + M2_STNDFF + e);
|
||||||
|
|
||||||
|
// ── Lid snap recesses on body exterior rim ────────────
|
||||||
|
// Front and rear pair
|
||||||
|
for (ys=[WALL/2, EXT_W - WALL/2 - SNAP_T]) {
|
||||||
|
translate([EXT_L/2 - SNAP_W/2, ys,
|
||||||
|
EXT_H - SNAP_H - 0.2])
|
||||||
|
cube([SNAP_W, SNAP_T + e, SNAP_H + 0.2]);
|
||||||
|
}
|
||||||
|
// Left and right pair
|
||||||
|
for (xs=[WALL/2, EXT_L - WALL/2 - SNAP_T]) {
|
||||||
|
translate([xs, EXT_W/2 - SNAP_W/2,
|
||||||
|
EXT_H - SNAP_H - 0.2])
|
||||||
|
cube([SNAP_T + e, SNAP_W, SNAP_H + 0.2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// enclosure_lid() Print: inside face down.
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module enclosure_lid() {
|
||||||
|
tol = 0.3;
|
||||||
|
lid_l = EXT_L + tol;
|
||||||
|
lid_w = EXT_W + tol;
|
||||||
|
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// Lid panel
|
||||||
|
rounded_box(lid_l, lid_w, LID_H, r = 3.5);
|
||||||
|
|
||||||
|
// Rim that drops over body (IP44 labyrinth)
|
||||||
|
translate([0, 0, -LID_OVLP])
|
||||||
|
difference() {
|
||||||
|
rounded_box(lid_l, lid_w, LID_OVLP, r = 3.5);
|
||||||
|
// Hollow inside rim
|
||||||
|
translate([WALL + tol/2, WALL + tol/2, -e])
|
||||||
|
cube([INT_L - tol, INT_W - tol, LID_OVLP + 2*e]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Labyrinth groove ridge (mates with body ridge)
|
||||||
|
translate([WALL - LID_LBYRTH_W + tol/2,
|
||||||
|
WALL - LID_LBYRTH_W + tol/2,
|
||||||
|
-LID_OVLP + LID_LBYRTH_H/2])
|
||||||
|
difference() {
|
||||||
|
rounded_box(INT_L + 2*LID_LBYRTH_W - tol,
|
||||||
|
INT_W + 2*LID_LBYRTH_W - tol,
|
||||||
|
LID_LBYRTH + 0.5, r = 2.5);
|
||||||
|
translate([LID_LBYRTH_W, LID_LBYRTH_W, -e])
|
||||||
|
cube([INT_L - tol, INT_W - tol,
|
||||||
|
LID_LBYRTH + 0.7]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── UWB antenna window (NO lid material over antenna) ─
|
||||||
|
// PCB centred in enclosure → antenna window centred in lid
|
||||||
|
bx = (lid_l - MAWB_L + 4) / 2;
|
||||||
|
by = (lid_w - MAWB_W + 4) / 2;
|
||||||
|
translate([bx, by, -e])
|
||||||
|
rounded_box(MAWB_L - 4, MAWB_W - 4,
|
||||||
|
LID_H + 2*e, r = 2);
|
||||||
|
|
||||||
|
// ── Snap tabs on inside of lid rim ────────────────────
|
||||||
|
for (ys=[WALL/2, lid_w - WALL/2 - SNAP_T]) {
|
||||||
|
translate([lid_l/2 - SNAP_W/2, ys,
|
||||||
|
-LID_OVLP + (LID_OVLP - SNAP_H)/2])
|
||||||
|
cube([SNAP_W, SNAP_T + e, SNAP_H]);
|
||||||
|
}
|
||||||
|
for (xs=[WALL/2, lid_l - WALL/2 - SNAP_T]) {
|
||||||
|
translate([xs, lid_w/2 - SNAP_W/2,
|
||||||
|
-LID_OVLP + (LID_OVLP - SNAP_H)/2])
|
||||||
|
cube([SNAP_T + e, SNAP_W, SNAP_H]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// belt_clip() Print: back face down. Use PETG for flex.
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module belt_clip() {
|
||||||
|
difference() {
|
||||||
|
union() {
|
||||||
|
// Back plate (mounts flush to Y− face of enclosure)
|
||||||
|
cube([EXT_L, CLIP_BACK_T, CLIP_H]);
|
||||||
|
|
||||||
|
// Outer spine
|
||||||
|
translate([0, CLIP_BACK_T, 0])
|
||||||
|
cube([EXT_L, CLIP_FLEX_T + CLIP_GAP, CLIP_H]);
|
||||||
|
|
||||||
|
// Top bridge
|
||||||
|
translate([0, CLIP_BACK_T, CLIP_H - CLIP_FLEX_T])
|
||||||
|
cube([EXT_L, CLIP_GAP + CLIP_FLEX_T + CLIP_BACK_T,
|
||||||
|
CLIP_FLEX_T]);
|
||||||
|
|
||||||
|
// Flex spring arm (tapers for compliance)
|
||||||
|
translate([EXT_L * 0.1, CLIP_BACK_T + CLIP_GAP, 0])
|
||||||
|
hull() {
|
||||||
|
cube([EXT_L * 0.8, CLIP_FLEX_T, 1]);
|
||||||
|
translate([EXT_L * 0.05, 1, CLIP_H - CLIP_FLEX_T - 4])
|
||||||
|
cube([EXT_L * 0.7, CLIP_FLEX_T + 1, 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Belt slot through outer spine
|
||||||
|
translate([(EXT_L - CLIP_BELT_W) / 2, CLIP_BACK_T - e,
|
||||||
|
CLIP_FLEX_T + 3])
|
||||||
|
cube([CLIP_BELT_W, CLIP_GAP + CLIP_FLEX_T + 2*e,
|
||||||
|
CLIP_H - 2*CLIP_FLEX_T - 6]);
|
||||||
|
|
||||||
|
// 2× M3 screws (clip → enclosure back face)
|
||||||
|
for (x = [EXT_L*0.25, EXT_L*0.75])
|
||||||
|
translate([x, -e, CLIP_H/2])
|
||||||
|
rotate([-90, 0, 0])
|
||||||
|
cylinder(d=3.3, h=CLIP_BACK_T + 2*e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// tpu_bumper() Print in TPU 95A. Snaps around body bottom.
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
module tpu_bumper() {
|
||||||
|
// Outer frame; inner cutout = body exterior + 0.5 clearance
|
||||||
|
cl = 0.5;
|
||||||
|
difference() {
|
||||||
|
// Outer rounded rectangle
|
||||||
|
translate([-TPU_T, -TPU_T, 0])
|
||||||
|
rounded_box(EXT_L + 2*TPU_T, EXT_W + 2*TPU_T,
|
||||||
|
TPU_H, r = TPU_CR);
|
||||||
|
|
||||||
|
// Inner cutout (fits over body)
|
||||||
|
translate([-cl/2, -cl/2, -e])
|
||||||
|
rounded_box(EXT_L + cl, EXT_W + cl,
|
||||||
|
TPU_H + 2*e, r = 3.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
// Render selector
|
||||||
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
if (RENDER == "assembly") {
|
||||||
|
color("SlateGray", 0.92) enclosure_body();
|
||||||
|
color("DimGray", 0.75) translate([0, 0, EXT_H])
|
||||||
|
enclosure_lid();
|
||||||
|
color("SteelBlue", 0.85) translate([0, -CLIP_BACK_T, 0])
|
||||||
|
belt_clip();
|
||||||
|
color("OrangeRed", 0.65) translate([0, 0, -TPU_H - 0.5])
|
||||||
|
tpu_bumper();
|
||||||
|
|
||||||
|
} else if (RENDER == "body") {
|
||||||
|
enclosure_body();
|
||||||
|
|
||||||
|
} else if (RENDER == "lid") {
|
||||||
|
enclosure_lid();
|
||||||
|
|
||||||
|
} else if (RENDER == "tpu_bumper") {
|
||||||
|
tpu_bumper();
|
||||||
|
|
||||||
|
} else if (RENDER == "body_2d") {
|
||||||
|
projection(cut = true)
|
||||||
|
translate([0, 0, -FLOOR/2])
|
||||||
|
enclosure_body();
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user