Explorar o código

Initial import: cable guide OpenSCAD models and STL outputs

Adds parametric cable guide design (cable_guide.scad, raw_cable.scad),
rendered STL files, JSON config, and reference data/drawings.
ZiB hai 4 meses
achega
b522ffb122
Modificáronse 8 ficheiros con 399 adicións e 0 borrados
  1. 38 0
      cable_guide.json
  2. 185 0
      cable_guide.scad
  3. BIN=BIN
      cable_guide.stl
  4. BIN=BIN
      data/213_drawing.png
  5. 20 0
      data/fillet_prompt.txt
  6. 37 0
      data/two_rects.scad
  7. 119 0
      raw_cable.scad
  8. BIN=BIN
      raw_cable.stl

+ 38 - 0
cable_guide.json

@@ -0,0 +1,38 @@
+{
+    "fileFormatVersion": "1",
+    "parameterSets": {
+        "New set 1": {
+            "ACT_D": "23.710000000000001",
+            "ACT_W": "48.549999999999997",
+            "ACT_X_OFFSET": "1.95",
+            "ACT_Y_OFFSET": "2.75",
+            "BEND_R": "2",
+            "BEND_WALL": "1.5",
+            "CHAM": "1",
+            "CHAM_ANGLE": "60",
+            "CORNER_R": "2.5",
+            "DISP_D": "29.199999999999999",
+            "DISP_T": "1",
+            "DISP_W": "59.200000000000003",
+            "DRAIN_D": "3",
+            "DRAIN_HOLES": "false",
+            "DRAIN_MARGIN": "1",
+            "FPC_LEN": "20",
+            "FPC_POCKET_D": "0.75",
+            "FPC_POCKET_L": "20",
+            "FPC_T": "0.29999999999999999",
+            "FPC_W": "12.5",
+            "LIP": "1.5",
+            "MAG_LIP_H": "2",
+            "MAG_TOL": "0.20000000000000001",
+            "SCREEN_EXPLODE": "0",
+            "SHOW_DISP": "true",
+            "SLICE_Y": "25",
+            "SLICE_Z": "0",
+            "TOL": "0.29999999999999999",
+            "WALL": "4.2000000000000002",
+            "X_PAD": "5",
+            "_sweep_half": "112.5"
+        }
+    }
+}

+ 185 - 0
cable_guide.scad

@@ -0,0 +1,185 @@
+// Waveshare 2.13" e-Paper HAT (B) — ESP32 Nametag Case
+// Display slides in from X−; FPC routes through internal 180° bend guide at X+
+
+// --- Display Dimensions (landscape: portrait rotated 90°) ---
+DISP_W = 59.20;   // overall width  (X) — portrait height
+DISP_D = 29.20;   // overall depth  (Y) — portrait width
+DISP_T = 1.0;     // thickness      (Z)
+
+// --- Active (Visible) Area ---
+ACT_W  = 48.55;   // active area width (X) — portrait AA height
+ACT_D  = 23.71;   // active area depth (Y) — portrait AA width
+
+// Border offsets from display edge to active area:
+//   X-: portrait top border  ≈ 1.95 mm  (open/entry side)
+//   X+: portrait FPC border  ≈ 8.70 mm  (closed/backstop; FPC exits here)
+//   Y±: symmetric            ≈ 2.75 mm  each side
+ACT_X_OFFSET = 1.95;
+ACT_Y_OFFSET = 2.75;
+
+// --- FPC Cable (exits X+ side of display) ---
+FPC_W   = 12.5;
+FPC_T   = 0.3;
+FPC_LEN = 20.0;   // visualization length of hanging tail
+
+// --- FPC Bend Guide ---
+BEND_R    = 2.0;   // inner bend radius (mm)
+BEND_WALL = 1.5;   // wall thickness around channel (mm)
+
+// --- FPC Excess-Cable Pocket (under display floor) ---
+FPC_POCKET_D = 0.75;  // depth below display floor (Z), slip-fit with assembly clearance
+FPC_POCKET_L = 20.0;  // length running toward X− from the X+ cavity wall
+
+// --- Resin Drain Holes (Z− face, under bend guide arc bottom) ---
+DRAIN_HOLES  = true;  // enable drain holes for SLA printing
+DRAIN_D      = 3.0;   // hole diameter (mm)
+DRAIN_MARGIN = 1.0;   // clearance from FPC cable corner to hole edge (mm)
+
+// --- Case Parameters ---
+WALL       = 4.2;   // = BEND_WALL + 2*BEND_R − DISP_T − TOL: keeps exactly BEND_WALL below channel
+LIP        = 1.5;   // front bezel lip thickness (Z)
+TOL        = 0.3;   // per-side display clearance
+CHAM       = 1.0;
+CHAM_ANGLE = 60;
+CORNER_R   = 2.5;
+X_PAD      = 0;     // extra bezel thickness added at X− (entry) end
+
+// --- Magnetic Strip Pocket (back face) ---
+MAG_L     = 1.772 * 25.4;   // strip length ≈ 45.01 mm
+MAG_W     = 0.512 * 25.4;   // strip width  ≈ 13.00 mm
+MAG_LIP_H = 2.0;             // pocket depth
+MAG_TOL   = 0.2;             // per-side clearance
+
+// --- Preview Controls ---
+SHOW_DISP      = false;
+SCREEN_EXPLODE = 0;     // mm to pull display toward X− in preview
+SLICE_Z        = 0;     // show only below this Z for cross-section view (0 = off)
+SLICE_Y        = 25;       // show only below this Y for cross-section view (0 = off)
+
+// --- Derived Dimensions ---
+cav_w     = DISP_W + TOL * 2;
+cav_d     = DISP_D + TOL * 2;
+case_w    = WALL + cav_w;          // WALL on X+; guide flat face at x=case_w
+case_h    = WALL + DISP_T + LIP;
+case_d    = WALL * 2 + cav_d;
+_guide_or = BEND_R + BEND_WALL;   // guide depth; case extends this far past case_w
+_guide_cz    = WALL + DISP_T + TOL - BEND_R;   // guide center Z: aligns guide top with entry slot top
+_sweep_half  = 112.5;                           // half of 225° sweep; arms exit at ±_sweep_half°
+_exit_x      = case_w + BEND_R * cos(-_sweep_half);   // X of bottom exit arm on inner radius
+_exit_z      = _guide_cz + BEND_R * sin(-_sweep_half); // Z of bottom exit arm on inner radius
+_exit_span_x = abs(BEND_R * cos(_sweep_half));         // X span from arc tip back to guide center
+
+_cham_xy = CHAM * tan(CHAM_ANGLE);
+
+// Drain holes: punched from Z− face up to just inside the arc bottom
+// Y offset keeps hole edges DRAIN_MARGIN clear of FPC cable corners (at ±FPC_W/2 from center)
+_drain_depth = _guide_cz - BEND_R + 0.5;          // 1.8 mm solid + 0.5 mm into arc
+_drain_y_off = FPC_W / 2 - DRAIN_D / 2 - DRAIN_MARGIN;  // inset from cable corner
+
+win_x = X_PAD + TOL + ACT_X_OFFSET;
+win_y = WALL + TOL + ACT_Y_OFFSET;
+
+// Magnetic strip pocket centered on full case length (including guide extension and X_PAD)
+_lip_il = MAG_L + 2 * MAG_TOL;
+_lip_iw = MAG_W + 2 * MAG_TOL;
+_lip_x  = (X_PAD + case_w + _guide_or) / 2 - _lip_il / 2;
+_lip_y  = case_d / 2 - _lip_iw / 2;
+
+// -------------------------------------------------------------------
+// Display mockup — approximate geometry for preview only
+// -------------------------------------------------------------------
+module EPD213B() {
+    color([0.82, 0.84, 0.80])
+        cube([DISP_W, DISP_D, DISP_T]);
+    color("white")
+        translate([ACT_X_OFFSET, ACT_Y_OFFSET, DISP_T])
+            cube([ACT_W, ACT_D, 0.02]);
+    color([1.0, 0.85, 0.1])
+        translate([DISP_W, (DISP_D - FPC_W) / 2, (DISP_T - FPC_T) / 2])
+            cube([FPC_LEN, FPC_W, FPC_T]);
+}
+
+// -------------------------------------------------------------------
+
+module rounded_box(l, w, h, r) {
+    hull()
+        for (dx = [r, l-r], dy = [r, w-r])
+            translate([dx, dy, 0]) cylinder(r=r, h=h, $fn=32);
+}
+
+module epd_case() {
+    _slot_w = FPC_W + 1.0;   // 0.5 mm per-side assembly clearance
+
+    difference() {
+        // Case body extended in X+ to enclose the bend guide, X_PAD extends X− end
+        rounded_box(X_PAD + case_w + _guide_or, case_d, case_h, CORNER_R);
+
+        // Display cavity — slot opens through X− face, extends full depth including X_PAD
+        translate([-0.01, WALL, WALL])
+            cube([X_PAD + cav_w + 0.01, cav_d, DISP_T + TOL]);
+
+        // Active area window + chamfered top edges
+        translate([win_x, win_y, WALL + DISP_T - 0.01])
+            cube([ACT_W, ACT_D, LIP - CHAM + 0.02]);
+        hull() {
+            translate([win_x, win_y, case_h - CHAM])
+                cube([ACT_W, ACT_D, 0.01]);
+            translate([win_x - _cham_xy, win_y - _cham_xy, case_h])
+                cube([ACT_W + 2*_cham_xy, ACT_D + 2*_cham_xy, 0.01]);
+        }
+
+        // Magnetic strip pocket in back face
+        translate([_lip_x, _lip_y, -0.01])
+            cube([_lip_il, _lip_iw, MAG_LIP_H + 0.01]);
+
+        // Combined cable channel — entry + return, interior walls removed
+        // Top is flat at WALL+DISP_T+TOL; floor slopes up from guide exit to cavity wall
+        hull() {
+            translate([X_PAD + _exit_x - 0.01, case_d / 2 - _slot_w / 2, _exit_z])
+                cube([_exit_span_x + 0.01, _slot_w, WALL + DISP_T + TOL - _exit_z]);
+            translate([X_PAD + cav_w - 0.01, case_d / 2 - _slot_w / 2, WALL - FPC_POCKET_D])
+                cube([0.02, _slot_w, DISP_T + TOL + FPC_POCKET_D]);
+        }
+
+        // FPC excess-cable pocket below display floor — cable coils here after the bend guide
+        translate([X_PAD + cav_w - FPC_POCKET_L, case_d / 2 - _slot_w / 2,
+                   WALL - FPC_POCKET_D])
+            cube([FPC_POCKET_L + 0.01, _slot_w, FPC_POCKET_D + 0.01]);
+
+        // Internal 225° bend guide channel
+        translate([X_PAD + case_w, case_d / 2, _guide_cz])
+        rotate([-90, 0, 0])
+        translate([0, 0, -_slot_w / 2])
+        linear_extrude(_slot_w)
+        intersection() {
+            circle(r = BEND_R, $fn = 64);
+            polygon(concat([[0, 0]],
+                [for (a = [112.5 : -5 : -112.5])
+                    [(BEND_R + 0.01) * cos(a), (BEND_R + 0.01) * sin(a)]]));
+        }
+
+        // Resin drain holes through Z− face at arc bottom
+        // Symmetric pair inset from FPC cable corners by DRAIN_MARGIN so cable glides past
+        if (DRAIN_HOLES)
+            for (s = [-1, 1])
+                translate([X_PAD + case_w, case_d / 2 + s * _drain_y_off, -0.01])
+                    cylinder(d = DRAIN_D, h = _drain_depth + 0.01, $fn = 32);
+
+
+}
+}
+
+// -------------------------------------------------------------------
+// Render
+// -------------------------------------------------------------------
+color("#004B49")
+    intersection() {
+        epd_case();
+        cube([X_PAD + case_w + _guide_or + 1,
+              ($preview && SLICE_Y > 0) ? SLICE_Y : case_d + 1,
+              ($preview && SLICE_Z > 0) ? SLICE_Z : case_h + 1]);
+    }
+
+if ($preview && SHOW_DISP)
+    translate([X_PAD + TOL - SCREEN_EXPLODE, WALL + TOL, WALL])
+        EPD213B();

BIN=BIN
cable_guide.stl


BIN=BIN
data/213_drawing.png


+ 20 - 0
data/fillet_prompt.txt

@@ -0,0 +1,20 @@
+When asked to add a fillet/rounded corner between two flat faces in OpenSCAD:
+
+Build the shape as a single extruded 2D cross-section rather than unioning separate solids.
+
+To place a circular arc exactly tangent to two planar faces meeting at a known angle:
+
+1. Express both face planes as line equations in the 2D cross-section plane.
+2. Solve for the circle centre that sits at distance r from both lines simultaneously. For two faces meeting where one is y=0 and the other is some line az + by = c, this is a system of two distance equations.
+3. The tangent point on each face is the foot of the perpendicular from the centre to that face — giving exact arc start/end angles via atan2.
+4. The arc sweeps between those two angles using a for loop inside a concat()-built polygon.
+5. Extrude the profile with linear_extrude, rotating as needed so extrusion goes in the correct world axis.
+
+For a specific common case — two panels of thickness t meeting at angle ang degrees, with the outer junction at the origin — the fillet centre is:
+- centre_y = r
+- centre_z = junction_z + r * (1 - 1/sin(ang/2 + 45)) (or derive directly from the two distance equations)
+
+The arc spans 180° down to 180° - ang° (for a junction where one face is vertical and the other tilts by ang).
+
+---
+The core lesson: don't round a sharp boolean union — compute the exact tangent circle analytically and build it into the profile from the start.

+ 37 - 0
data/two_rects.scad

@@ -0,0 +1,37 @@
+// Two 10x10 mm panels meeting at one edge, 45-degree dihedral angle,
+// with a rounded fillet on the outer face of the junction.
+
+t = 2;   // panel thickness
+s = 10;  // panel size (10x10 mm face)
+r = 2;   // fillet radius
+$fn = 64;
+
+// Cross-section is built in the YZ plane, extruded in X.
+//
+// Panel 1 outer face: y=0
+// Panel 2 outer face: z = y+10  (i.e. the plane after 45-deg pivot)
+//
+// Fillet circle tangent to both faces at distance r:
+//   centre_y = r
+//   centre_z = 10 + r*(1 - sqrt(2))
+//
+// Tangent point on Panel 1 face (y=0) is at angle 180° from centre.
+// Tangent point on Panel 2 face is at angle 135° from centre.
+// Arc sweeps 180° → 135°.
+
+fc = [r, 10 + r*(1 - sqrt(2))];
+
+rotate([90, 0, 90])
+linear_extrude(s)
+polygon(concat(
+  // Panel 1 outer face: bottom to fillet start
+  [[0, 0]],
+  // Fillet arc (180° → 135°)
+  [for (a = [180:-1:135]) [fc[0]+r*cos(a), fc[1]+r*sin(a)]],
+  // Panel 2 outer face: fillet end to far tip
+  [[s*sin(45), 10+s*cos(45)]],
+  // Across Panel 2 far end, down Panel 2 inner face, down Panel 1 inner face
+  [[s*sin(45)+t*cos(45), 10+s*cos(45)-t*sin(45)],
+   [t, fc[1]],
+   [t, 0]]
+));

+ 119 - 0
raw_cable.scad

@@ -0,0 +1,119 @@
+// Waveshare 2.13" e-Paper HAT (B) — ESP32 Nametag Case
+// Display slides in from X+; FPC cable exits freely out the open X+ side
+
+// --- Display Dimensions (landscape: portrait rotated 90°) ---
+DISP_W = 59.20;   // overall width  (X) — portrait height
+DISP_D = 29.20;   // overall depth  (Y) — portrait width
+DISP_T = 1.0;     // thickness      (Z)
+
+// --- Active (Visible) Area ---
+ACT_W  = 48.55;   // active area width (X) — portrait AA height
+ACT_D  = 23.71;   // active area depth (Y) — portrait AA width
+
+// Border offsets from display edge to active area:
+//   X-: portrait top border  ≈ 1.95 mm  (closed/backstop side)
+//   X+: portrait FPC border  ≈ 8.70 mm  (open/entry side)
+//   Y±: symmetric            ≈ 2.75 mm  each side
+ACT_X_OFFSET = 1.95;
+ACT_Y_OFFSET = 2.75;
+
+// --- FPC Cable (exits X+ side) ---
+FPC_W   = 12.5;
+FPC_T   = 0.3;
+FPC_LEN = 20.0;   // visualization length of hanging tail
+
+// --- Case Parameters ---
+WALL       = 3.0;   // must exceed MAG_LIP_H (2.0) to keep pocket floor
+LIP        = 1.5;   // front bezel lip thickness (Z)
+TOL        = 0.3;   // per-side display clearance
+CHAM       = 1.0;
+CHAM_ANGLE = 60;
+CORNER_R   = 2.5;
+CLIP_Z     = 0;     // preview: mm to remove from Z+ (0 = full model)
+SHOW_DISP  = true;
+SCREEN_EXPLODE    = 0;     // mm to pull display toward X+ in preview
+
+// --- Magnetic Strip Locating Lip (rear face) ---
+MAG_L        = 1.772 * 25.4;   // strip length ≈ 45.01 mm
+MAG_W        = 0.512 * 25.4;   // strip width  ≈ 13.00 mm
+MAG_LIP_H    = 2.0;            // lip height protruding from rear face
+MAG_LIP_WALL = 1.0;            // lip wall thickness
+MAG_TOL      = 0.2;            // per-side clearance for strip fit
+
+// --- Derived Dimensions ---
+cav_w  = DISP_W + TOL * 2;
+cav_d  = DISP_D + TOL * 2;
+case_w = WALL + cav_w;          // no X+ wall; open for display entry
+case_h = WALL + DISP_T + LIP;
+case_d = WALL * 2 + cav_d;
+
+_cham_xy = CHAM * tan(CHAM_ANGLE);
+
+win_x = WALL + TOL + ACT_X_OFFSET;
+win_y = WALL + TOL + ACT_Y_OFFSET;
+
+// Magnetic strip recess geometry (centered on back face)
+_lip_il = MAG_L + 2 * MAG_TOL;
+_lip_iw = MAG_W + 2 * MAG_TOL;
+_lip_x  = case_w / 2 - _lip_il / 2;
+_lip_y  = case_d / 2 - _lip_iw / 2;
+
+// -------------------------------------------------------------------
+// Display mockup — approximate geometry for preview only
+// -------------------------------------------------------------------
+module EPD213B() {
+    color([0.82, 0.84, 0.80])
+        cube([DISP_W, DISP_D, DISP_T]);
+    color("white")
+        translate([ACT_X_OFFSET, ACT_Y_OFFSET, DISP_T])
+            cube([ACT_W, ACT_D, 0.02]);
+    color([1.0, 0.85, 0.1])
+        translate([DISP_W, (DISP_D - FPC_W) / 2, (DISP_T - FPC_T) / 2])
+            cube([FPC_LEN, FPC_W, FPC_T]);
+}
+
+// -------------------------------------------------------------------
+
+module rounded_box(l, w, h, r) {
+    hull()
+        for (dx = [r, l-r], dy = [r, w-r])
+            translate([dx, dy, 0]) cylinder(r=r, h=h, $fn=32);
+}
+
+module epd_case() {
+    difference() {
+        rounded_box(case_w, case_d, case_h, CORNER_R);
+
+        // Display cavity — extends 0.01 mm past X+ face to leave that side open
+        translate([WALL, WALL, WALL])
+            cube([cav_w + 0.01, cav_d, DISP_T + TOL]);
+
+        // Active area window + chamfered top edges
+        translate([win_x, win_y, WALL + DISP_T - 0.01])
+            cube([ACT_W, ACT_D, LIP - CHAM + 0.02]);
+        hull() {
+            translate([win_x, win_y, case_h - CHAM])
+                cube([ACT_W, ACT_D, 0.01]);
+            translate([win_x - _cham_xy, win_y - _cham_xy, case_h])
+                cube([ACT_W + 2*_cham_xy, ACT_D + 2*_cham_xy, 0.01]);
+        }
+
+        // Magnetic strip recess in back face
+        translate([_lip_x, _lip_y, -0.01])
+            cube([_lip_il, _lip_iw, MAG_LIP_H + 0.01]);
+    }
+}
+
+color("#004B49")
+    intersection() {
+        epd_case();
+        cube([case_w + 1, case_d + 1,
+              ($preview && CLIP_Z > 0)
+                  ? max(0.01, case_h - CLIP_Z)
+                  : case_h + 1]);
+    }
+
+if ($preview && SHOW_DISP)
+    translate([WALL + TOL + SCREEN_EXPLODE, WALL + TOL, WALL])
+        EPD213B();
+

BIN=BIN
raw_cable.stl