// ============================================================ // XIAO ePaper Display Board EE04 — 3D-Printed Case (base only) // OpenSCAD parametric model // ============================================================ include use /* [Preview] */ SHOW_BOARD = true; SHOW_BATTERY = true; // ============================================================ // HELPERS // ============================================================ // Standoff boss: screw variant has through-hole; stud variant has locating pin instead. // Diagonal (X1,Y1)+(X2,Y2) → studs; (X1,Y2)+(X2,Y1) → screws. module pcb_boss(px, py, stud=false) { translate([PCB_OX + px, PCB_OY + py, FLOOR]) { difference() { cylinder(d=BOSS_D, h=BOSS_H + 0.01, $fn=24); if (!stud) translate([0, 0, -0.1]) cylinder(d=SCREW_D * 0.7, h=BOSS_H + 0.2, $fn=18); } if (stud) translate([0, 0, BOSS_H]) { cylinder(r=STUD_R, h=STUD_H, $fn=24); translate([0, 0, STUD_H]) sphere(r=STUD_R, $fn=24); } } } // ============================================================ // BASE // ============================================================ module base() { color("#004B49") { difference() { rounded_box(OUT_L, OUT_W, BASE_H, CORNER_R); // Interior cavity (open top) translate([WALL, WALL, FLOOR]) cube([CAV_L, CAV_W, BASE_H]); // ---- Boss screw holes through 50 % of floor (screw diagonal only) ---- for (pos = [[PCB_BOSS_X1, PCB_BOSS_Y2], [PCB_BOSS_X2, PCB_BOSS_Y1]]) translate([PCB_OX + pos[0], PCB_OY + pos[1], FLOOR * 0.5 - 0.1]) cylinder(d=SCREW_D * 0.7, h=FLOOR * 0.5 + 0.2, $fn=18); // ---- +Y wall cutouts ---- // Sliding power switch pocket — closed exterior face, interior clearance only translate([PCB_OX + PWR_CX - PWR_W/2, OUT_W - WALL - 0.1, PCB_Z + PWR_CZ - PWR_H/2]) cube([PWR_W, WALL - PWR_COVER_T + 0.1, PWR_H]); // USB-C slot translate([PCB_OX + USBC_CX - (USBC_W + 2*USBC_CBL_CLEAR)/2, OUT_W - WALL - 0.1, PCB_Z + USBC_CZ - (USBC_H + 2*USBC_CBL_CLEAR)/2]) cube([USBC_W + 2*USBC_CBL_CLEAR, WALL + 0.2, USBC_H + 2*USBC_CBL_CLEAR]); // 4× button holes (3 user + 1 reset) for (bcx = BTN_CX) translate([PCB_OX + bcx, OUT_W + 0.1, PCB_Z + BTN_CZ]) rotate([90, 0, 0]) cylinder(d=BTN_D, h=WALL + 0.3, $fn=32); // ---- Y- wall step for lid flange clearance ---- // Remove the full Y- wall above z=BASE_H-FLANGE_H-SLIDE_CLEAR so the lid // flanges can enter freely from Y-. translate([-0.1, -0.1, BASE_H - FLANGE_H - SLIDE_CLEAR]) cube([OUT_L + 0.2, WALL + 0.2, FLANGE_H + SLIDE_CLEAR + 0.1]); } // Standoff bosses (added outside diff so cavity doesn't subtract them) pcb_boss(PCB_BOSS_X1, PCB_BOSS_Y1, stud=true); // stud diagonal pcb_boss(PCB_BOSS_X2, PCB_BOSS_Y2, stud=true); // stud diagonal pcb_boss(PCB_BOSS_X1, PCB_BOSS_Y2, stud=false); // screw diagonal pcb_boss(PCB_BOSS_X2, PCB_BOSS_Y1, stud=false); // screw diagonal } // Lid-retention flanges — right triangles, wide face flush with case top (z=BASE_H), // tip pointing down to (WALL, BASE_H-FLANGE_H). Hypotenuse faces down-into-cavity; // lid flanges slide underneath it for Z retention. color("#2C3863") { hull() { translate([WALL, WALL, BASE_H - 0.01]) cube([FLANGE_W, CAV_W, 0.01]); translate([WALL, WALL, BASE_H - FLANGE_H]) cube([0.01, CAV_W, 0.01]); } hull() { translate([OUT_L - WALL - FLANGE_W, WALL, BASE_H - 0.01]) cube([FLANGE_W, CAV_W, 0.01]); translate([OUT_L - WALL - 0.01, WALL, BASE_H - FLANGE_H]) cube([0.01, CAV_W, 0.01]); } // Y+ locking flanges — same angled profile as side flanges, in YZ plane; // split around FPC notch for cable clearance for (seg = [ [WALL, PCB_OX + FPC_CX - FPC_NOTCH_W/2 - WALL], [PCB_OX + FPC_CX + FPC_NOTCH_W/2, OUT_L - WALL - (PCB_OX + FPC_CX + FPC_NOTCH_W/2)] ]) hull() { translate([seg[0], OUT_W - WALL - FLANGE_W, BASE_H - 0.01]) cube([seg[1], FLANGE_W, 0.01]); translate([seg[0], OUT_W - WALL - 0.01, BASE_H - FLANGE_H]) cube([seg[1], 0.01, 0.01]); } } } // ============================================================ // PREVIEW-ONLY COMPONENTS // ============================================================ module stl_board() { translate([PCB_OX, PCB_OY, PCB_Z]) EE04(); } module battery() { color("darkgray", 0.85) translate([CAV_L - BATT_W - CLR_BATX, CAV_W - BATT_D - CLR_BATY, FLOOR + 0.01]) cube([BATT_W, BATT_D, BATT_T]); } // ============================================================ // RENDER // ============================================================ base(); if ($preview) { if (SHOW_BOARD) stl_board(); if (SHOW_BATTERY) battery(); }