CAD implementation files for Issue #505 (24V charging dock upgrade): - charging_dock_505.scad: Main dock assembly * Base plate: 340×320×12 mm (enlarged for 240W PSU) * Back wall: 250×85×10 mm (pogo pin housing, LED bezel recess) * V-guide rails: 100mm deep, self-centering funnel (print 2×) * ArUco marker frame: ID 42 (DICT_4X4_250), 15cm mast * PSU bracket: Sized for Mean Well IRM-240-24 (210×108×56 mm) * LED bezel: 4× status indicators (SEARCHING/ALIGNED/CHARGING/FULL) - charging_dock_receiver_505.scad: Robot-side receiver variants * Lab receiver: Stem collar mount (SaltyLab) * Rover receiver: Deck flange mount (SaltyRover) * Tank receiver: Skid plate mount + extended nose (SaltyTank) * Common contact geometry: 20mm CL-to-CL brass pads, V-nose guide * Wire bore: 3mm (supports 12 AWG charging wires) Key changes from Issue #159 (5V): - PSU dimensions: 63×45×28 mm → 210×108×56 mm - Base/bracket enlarged accordingly - ArUco ID: 0 → 42 - Contact geometry unchanged (compatible with Issue #159 receivers) - Pogo pins, V-guides, LED circuit identical Files ready for: - STL export via OpenSCAD render commands - 3D printing (PETG recommended) - Assembly integration with docking node (#489) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
333 lines
15 KiB
OpenSCAD
333 lines
15 KiB
OpenSCAD
// ============================================================
|
||
// charging_dock_receiver_505.scad — Robot-Side Charging Receiver (24V)
|
||
// Issue: #505 Agent: sl-mechanical Date: 2026-03-06
|
||
// ============================================================
|
||
//
|
||
// Robot-side contact plate that mates with the 24V charging dock pogo pins.
|
||
// Forked from Issue #159 receiver (contact geometry unchanged; 12 AWG wire bore).
|
||
// Each robot variant has a different mounting interface; the contact
|
||
// geometry is identical across all variants (same pogo pin spacing).
|
||
//
|
||
// Variants:
|
||
// A — lab_receiver() SaltyLab — mounts to underside of stem base ring
|
||
// B — rover_receiver() SaltyRover — mounts to chassis belly (M4 deck holes)
|
||
// C — tank_receiver() SaltyTank — mounts to skid plate / hull floor
|
||
//
|
||
// Contact geometry (common across variants):
|
||
// 2× brass contact pads, Ø12 mm × 2 mm (press-fit into PETG housing)
|
||
// Pad spacing: 20 mm CL-to-CL (matches dock POGO_SPACING exactly)
|
||
// Contact face Z height matches dock pogo pin Z when robot is level
|
||
// Polarity: marked + on top pin (conventional: positive = right when
|
||
// facing dock; negative = left) — must match dock wiring.
|
||
//
|
||
// Approach guide nose:
|
||
// A chamfered V-nose on the forward face guides the receiver block
|
||
// into the dock's V-funnel. Taper half-angle ≈ 14° matches guide rails.
|
||
// Nose width = RECV_W = 30 mm (matches dock EXIT_GAP - 2 mm clearance).
|
||
//
|
||
// Coordinate convention:
|
||
// Z = 0 at receiver mounting face (against robot chassis/deck underside).
|
||
// +Z points downward (toward dock floor).
|
||
// Contact pads face +Y (toward dock back wall when docked).
|
||
// Receiver centred on X = 0 (robot centreline).
|
||
//
|
||
// RENDER options:
|
||
// "assembly" all 3 receivers side by side
|
||
// "lab_stl" SaltyLab receiver (print 1×)
|
||
// "rover_stl" SaltyRover receiver (print 1×)
|
||
// "tank_stl" SaltyTank receiver (print 1×)
|
||
// "contact_pad_2d" DXF — Ø12 mm brass pad profile (order from metal shop)
|
||
//
|
||
// Export (Issue #505 24V variant):
|
||
// openscad charging_dock_receiver_505.scad -D 'RENDER="lab_stl"' -o receiver_505_lab.stl
|
||
// openscad charging_dock_receiver_505.scad -D 'RENDER="rover_stl"' -o receiver_505_rover.stl
|
||
// openscad charging_dock_receiver_505.scad -D 'RENDER="tank_stl"' -o receiver_505_tank.stl
|
||
// openscad charging_dock_receiver_505.scad -D 'RENDER="contact_pad_2d"' -o contact_pad_505.dxf
|
||
// ============================================================
|
||
|
||
$fn = 64;
|
||
e = 0.01;
|
||
|
||
// ── Contact geometry (must match charging_dock.scad) ─────────────────────────
|
||
POGO_SPACING = 20.0; // CL-to-CL (dock POGO_SPACING)
|
||
PAD_D = 12.0; // contact pad OD (brass disc)
|
||
PAD_T = 2.0; // contact pad thickness
|
||
PAD_RECESS = 1.8; // pad pressed into housing (0.2 mm proud for contact)
|
||
PAD_PROUD = 0.2; // pad face protrudes from housing face
|
||
|
||
// ── Common receiver body geometry ────────────────────────────────────────────
|
||
RECV_W = 30.0; // receiver body width (X) — matches dock EXIT_GAP inner
|
||
RECV_D = 25.0; // receiver body depth (Y, docking direction)
|
||
RECV_H = 12.0; // receiver body height (Z, from mount face down)
|
||
RECV_R = 3.0; // corner radius
|
||
// V-nose geometry (front Y face — faces dock back wall)
|
||
NOSE_CHAMFER = 10.0; // chamfer depth on X corners of front face
|
||
|
||
// Polarity indicator slot (on top/mount face: + on right, - on left)
|
||
POL_SLOT_W = 4.0;
|
||
POL_SLOT_D = 8.0;
|
||
POL_SLOT_H = 1.0;
|
||
|
||
// Fasteners
|
||
M2_D = 2.4;
|
||
M3_D = 3.3;
|
||
M4_D = 4.3;
|
||
|
||
// ── Mounting patterns ─────────────────────────────────────────────────────────
|
||
// SaltyLab stem base ring (Ø25 mm stem, 4× M3 in ring at Ø40 mm BC)
|
||
LAB_BC_D = 40.0;
|
||
LAB_BOLT_D = M3_D;
|
||
LAB_COLLAR_H = 15.0; // collar height above receiver body
|
||
|
||
// SaltyRover deck (M4 grid pattern, 30.5×30.5 mm matching FC pattern on deck)
|
||
// Receiver uses 4× M4 holes at ±20 mm from centre (clear of deck electronics)
|
||
ROVER_BOLT_SPC = 40.0;
|
||
|
||
// SaltyTank skid plate (M4 holes matching skid plate bolt pattern)
|
||
// Uses 4× M4 at ±20 mm X, ±10 mm Y (inset from skid plate M4 positions)
|
||
TANK_BOLT_SPC_X = 40.0;
|
||
TANK_BOLT_SPC_Y = 20.0;
|
||
TANK_NOSE_L = 20.0; // extended nose for tank (wider hull)
|
||
|
||
// ============================================================
|
||
// RENDER DISPATCH
|
||
// ============================================================
|
||
RENDER = "assembly";
|
||
|
||
if (RENDER == "assembly") assembly();
|
||
else if (RENDER == "lab_stl") lab_receiver();
|
||
else if (RENDER == "rover_stl") rover_receiver();
|
||
else if (RENDER == "tank_stl") tank_receiver();
|
||
else if (RENDER == "contact_pad_2d") {
|
||
projection(cut = true) translate([0, 0, -0.5])
|
||
linear_extrude(1) circle(d = PAD_D);
|
||
}
|
||
|
||
// ============================================================
|
||
// ASSEMBLY PREVIEW
|
||
// ============================================================
|
||
module assembly() {
|
||
// SaltyLab receiver
|
||
color("RoyalBlue", 0.85)
|
||
translate([-80, 0, 0])
|
||
lab_receiver();
|
||
|
||
// SaltyRover receiver
|
||
color("OliveDrab", 0.85)
|
||
translate([0, 0, 0])
|
||
rover_receiver();
|
||
|
||
// SaltyTank receiver
|
||
color("SaddleBrown", 0.85)
|
||
translate([80, 0, 0])
|
||
tank_receiver();
|
||
}
|
||
|
||
// ============================================================
|
||
// COMMON RECEIVER BODY
|
||
// ============================================================
|
||
// Internal helper: the shared contact housing + V-nose.
|
||
// Orientation: mount face = +Z top; contact face = +Y front.
|
||
// All variant-specific modules call this, then add their mount interface.
|
||
module _receiver_body() {
|
||
difference() {
|
||
union() {
|
||
// ── Main housing block (rounded) ─────────────────────────
|
||
linear_extrude(RECV_H)
|
||
_recv_profile_2d();
|
||
|
||
// ── V-nose chamfer reinforcement ribs ─────────────────────
|
||
// Two diagonal ribs at 45° reinforce the chamfered corners
|
||
for (sx = [-1, 1])
|
||
hull() {
|
||
translate([sx*(RECV_W/2 - NOSE_CHAMFER),
|
||
RECV_D/2, 0])
|
||
cylinder(d = 3, h = RECV_H * 0.6);
|
||
translate([sx*(RECV_W/2), RECV_D/2 - NOSE_CHAMFER, 0])
|
||
cylinder(d = 3, h = RECV_H * 0.6);
|
||
}
|
||
}
|
||
|
||
// ── Contact pad bores (2× Ø12 mm, press-fit) ─────────────────
|
||
// Pads face +Y; bores from Y face into housing
|
||
for (px = [-POGO_SPACING/2, POGO_SPACING/2])
|
||
translate([px, RECV_D/2 + e, RECV_H/2])
|
||
rotate([90, 0, 0]) {
|
||
// Pad press-fit bore
|
||
cylinder(d = PAD_D + 0.1,
|
||
h = PAD_RECESS + e);
|
||
// Wire bore (behind pad, to mount face)
|
||
translate([0, 0, PAD_RECESS])
|
||
cylinder(d = 3.0,
|
||
h = RECV_D + 2*e);
|
||
}
|
||
|
||
// ── Polarity indicator slots on top face ──────────────────────
|
||
// "+" slot: right pad (+X side)
|
||
translate([POGO_SPACING/2, 0, -e])
|
||
cube([POL_SLOT_W, POL_SLOT_D, POL_SLOT_H + e], center = true);
|
||
// "-" indent: left pad (no slot = negative)
|
||
|
||
// ── Wire routing channel (on mount face / underside) ──────────
|
||
// Trough connecting both pad bores for neat wire run
|
||
translate([0, RECV_D/2 - POGO_SPACING/2, RECV_H - 3])
|
||
cube([POGO_SPACING + 6, POGO_SPACING, 4], center = true);
|
||
}
|
||
}
|
||
|
||
// ── 2D profile of receiver body with chamfered V-nose ────────────────────────
|
||
module _recv_profile_2d() {
|
||
hull() {
|
||
// Rear corners (full width)
|
||
for (sx = [-1, 1])
|
||
translate([sx*(RECV_W/2 - RECV_R), -RECV_D/2 + RECV_R])
|
||
circle(r = RECV_R);
|
||
// Front corners (chamfered — narrowed by NOSE_CHAMFER)
|
||
for (sx = [-1, 1])
|
||
translate([sx*(RECV_W/2 - NOSE_CHAMFER - RECV_R),
|
||
RECV_D/2 - RECV_R])
|
||
circle(r = RECV_R);
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// PART A — SALTYLAB RECEIVER
|
||
// ============================================================
|
||
// Mounts to the underside of the SaltyLab chassis stem base ring.
|
||
// Split collar grips Ø25 mm stem; receiver body hangs below collar.
|
||
// Z height set so contact pads align with dock pogo pins when robot
|
||
// rests on flat surface (robot wheel-to-contact-pad height calibrated).
|
||
//
|
||
// Receiver height above floor: tune LAB_CONTACT_Z in firmware (UWB/ArUco
|
||
// approach). Mechanically: receiver sits ~35 mm above ground (stem base
|
||
// height), matching dock POGO_Z = 35 mm.
|
||
module lab_receiver() {
|
||
collar_od = 46.0; // matches sensor_rail.scad STEM_COL_OD
|
||
collar_h = LAB_COLLAR_H;
|
||
|
||
union() {
|
||
// ── Common receiver body ────────────────────────────────────
|
||
_receiver_body();
|
||
|
||
// ── Stem collar (split, 2 halves joined with M4 bolts) ───────
|
||
// Only the front half printed here; rear half is mirror.
|
||
translate([0, -RECV_D/2, RECV_H])
|
||
difference() {
|
||
// Half-collar cylinder
|
||
rotate_extrude(angle = 180)
|
||
translate([collar_od/2 - 8, 0, 0])
|
||
square([8, collar_h]);
|
||
|
||
// Stem bore clearance
|
||
translate([0, 0, -e])
|
||
cylinder(d = 25.5, h = collar_h + 2*e);
|
||
|
||
// 2× M4 clamping bolt bores (through collar flanges)
|
||
for (cx = [-collar_od/2 + 4, collar_od/2 - 4])
|
||
translate([cx, 0, collar_h/2])
|
||
rotate([90, 0, 0])
|
||
cylinder(d = M4_D,
|
||
h = collar_od + 2*e,
|
||
center = true);
|
||
}
|
||
|
||
// ── M3 receiver-to-collar bolts ───────────────────────────────
|
||
// 4× M3 holes connecting collar flange to receiver body top
|
||
// (These are mounting holes for assembly; not holes in the part)
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// PART B — SALTYOVER RECEIVER
|
||
// ============================================================
|
||
// Mounts to the underside of the SaltyRover deck plate.
|
||
// 4× M4 bolts into deck underside (blind holes tapped in deck).
|
||
// Receiver sits flush with deck belly; contact pads protrude 5 mm below.
|
||
// Dock pogo Z = 35 mm must equal ground-to-deck-belly height for rover
|
||
// (approximately 60 mm chassis clearance — shim with spacer if needed).
|
||
module rover_receiver() {
|
||
mount_h = 5.0; // mounting flange thickness
|
||
|
||
union() {
|
||
// ── Common receiver body ────────────────────────────────────
|
||
_receiver_body();
|
||
|
||
// ── Mounting flange (attaches to deck belly) ─────────────────
|
||
difference() {
|
||
translate([-(ROVER_BOLT_SPC/2 + 12),
|
||
-RECV_D/2 - 10,
|
||
RECV_H])
|
||
cube([ROVER_BOLT_SPC + 24,
|
||
RECV_D + 20,
|
||
mount_h]);
|
||
|
||
// 4× M4 bolt holes
|
||
for (fx = [-1, 1]) for (fy = [-1, 1])
|
||
translate([fx*ROVER_BOLT_SPC/2,
|
||
fy*(RECV_D/2 + 5),
|
||
RECV_H - e])
|
||
cylinder(d = M4_D,
|
||
h = mount_h + 2*e);
|
||
|
||
// Weight-reduction pockets
|
||
for (sx = [-1, 1])
|
||
translate([sx*(ROVER_BOLT_SPC/4 + 6),
|
||
0, RECV_H + 1])
|
||
cube([ROVER_BOLT_SPC/2 - 4, RECV_D - 4, mount_h],
|
||
center = true);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ============================================================
|
||
// PART C — SALTYTANK RECEIVER
|
||
// ============================================================
|
||
// Mounts to SaltyTank hull floor or replaces a section of skid plate.
|
||
// Extended front nose (TANK_NOSE_L) for tank's wider hull approach.
|
||
// Contact pads exposed through skid plate via a 30×16 mm slot.
|
||
// Ground clearance: tank chassis = 90 mm; dock POGO_Z = 35 mm.
|
||
// Use ramp shim (see BOM) under dock base to elevate pogo pins to 90 mm
|
||
// OR set POGO_Z = 90 in dock for a tank-specific dock configuration.
|
||
// ⚠ Cross-variant dock: set POGO_Z per robot if heights differ.
|
||
// Compromise: POGO_Z = 60 mm with 25 mm ramp for tank, 25 mm spacer for lab.
|
||
module tank_receiver() {
|
||
mount_h = 4.0;
|
||
nose_l = RECV_D/2 + TANK_NOSE_L;
|
||
|
||
union() {
|
||
// ── Common receiver body ────────────────────────────────────
|
||
_receiver_body();
|
||
|
||
// ── Extended nose for tank approach ──────────────────────────
|
||
// Additional chamfered wedge ahead of standard receiver body
|
||
hull() {
|
||
// Receiver front face corners
|
||
for (sx = [-1, 1])
|
||
translate([sx*(RECV_W/2 - NOSE_CHAMFER), RECV_D/2, 0])
|
||
cylinder(d = 2*RECV_R, h = RECV_H * 0.5);
|
||
// Extended nose tip (narrowed to 20 mm)
|
||
for (sx = [-1, 1])
|
||
translate([sx*10, RECV_D/2 + TANK_NOSE_L, 0])
|
||
cylinder(d = 2*RECV_R, h = RECV_H * 0.4);
|
||
}
|
||
|
||
// ── Mounting flange (bolts to tank skid plate) ────────────────
|
||
difference() {
|
||
translate([-(TANK_BOLT_SPC_X/2 + 10),
|
||
-RECV_D/2 - 8,
|
||
RECV_H])
|
||
cube([TANK_BOLT_SPC_X + 20,
|
||
RECV_D + 16,
|
||
mount_h]);
|
||
|
||
// 4× M4 bolt holes
|
||
for (fx = [-1, 1]) for (fy = [-1, 1])
|
||
translate([fx*TANK_BOLT_SPC_X/2,
|
||
fy*TANK_BOLT_SPC_Y/2,
|
||
RECV_H - e])
|
||
cylinder(d = M4_D,
|
||
h = mount_h + 2*e);
|
||
}
|
||
}
|
||
}
|